分区SQL Server函数 Partition By 与 row_number() 、 排序rank()的用法

在 SQL Server 中,PARTITION BY 是用于在窗口函数(如 ROW_NUMBER(), RANK(), DENSE_RANK(), SUM(), AVG(), 等等)中定义分区的一种方法。分区允许你在查询结果集的特定子集中应用窗口函数,而不是在整个结果集上应用。

使用场景
‌1.排名‌:如上面的例子,可以使用 ROW_NUMBER(), RANK(), 或 DENSE_RANK() 来计算分区内的排名。
2‌.累积和/移动平均‌:可以使用 SUM(), AVG() 等聚合函数来计算分区内的累积和或移动平均。
‌3.分组计算‌:可以在每个分区内执行特定的计算,而不需要使用子查询或 GROUP BY。

举个例子,我们先准备好一个学生成绩表的数据源

create table Student  --学生成绩表
(
 id int,  --主键
 Grade int, --班级
 Score int --分数
);

insert into Student values(1,1,88); 
insert into Student values(2,1,66); 
insert into Student values(3,1,75); 
insert into Student values(4,2,30); 
insert into Student values(5,2,70); 
insert into Student values(6,2,80); 
insert into Student values(7,2,60); 
insert into Student values(8,3,90); 
insert into Student values(9,3,70); 
insert into Student values(10,3,80); 
insert into Student values(11,3,80)

一:如果我们想要一个输出每个学生成绩名次的结果,就可以使用row_number() 方法,配合排序

select *,row_number() over(order by Score desc) as Sequence from Student

二:如果我们想要对每个年级的学生的名词分别计算,那就要使用到partition by方法

select *,row_number() over(partition by Grade order by Score desc) as Sequence from Student

接下来,我们还可以利用上述结果进行二次筛选,比如获取每个年级第一名

select * from (
    select *,row_number() over(partition by Grade order by Score desc) as Sequence from Student
  ) T 
where T.Sequence<=1

在这里,我们发现一个现象,当存在一个分数一样的情况,比如三年级有2个80分,但是他们的排名却分了前后,如果要想排名一致,都是第二名,就可以使用rank()方法

三:按照年级,输出每个学生的排名,同分数排名一致

select *,rank() over(partition by Grade order by Score desc) as Sequence from Student;

此时,我们再获取每个年级前2名,就可以取出分数并列第二名的同学

select * from (
    select *,rank() over(partition by Grade order by Score desc) as Sequence from Student
  ) T 
where T.Sequence<=2

注意事项
PARTITION BY 子句中的列应仔细选择,因为它们会影响查询的性能。
如果不需要分区,可以省略 PARTITION BY 子句,此时窗口函数将在整个结果集上应用。
可以结合多个列进行分区,例如 PARTITION BY Grade。
通过使用 PARTITION BY,你可以更灵活和高效地进行数据分析和处理,尤其是在处理大型数据集时。

SQL SERVER批量还原数据库

通常,迁移服务器后,往往需要还原SQLSERVER的备份文件,如果BAK文件一多,恢复起来就比较费时间,以下可以通过SQL脚本的方法,进行批量还原SQLSERVER的备份文件,注意:需要指定 备份文件所在文件夹路径,还有 数据库安装路径中的数据文件夹路径,

1.首先把后缀为bak的备份文件放到指定盘目录上,例如“D:\db\”文件夹

2.找到数据库的安装路径下的数据库目录文件,例如“D:\Software\SQL2014\DB\MSSQL12.MSSQLSERVER\MSSQL\DATA\”

3.修改脚本里对应的目录配置,执行SQL脚本,具体脚本如下

DECLARE @SqlServerPath NVARCHAR(200) --数据库安装路径(数据文件夹)
DECLARE @BackUpPath NVARCHAR(200) --备份文件路径
DECLARE @BackUpFileName NVARCHAR(200) --备份文件名
DECLARE @DbName NVARCHAR(200) --db名称
DECLARE @LogicalDbName NVARCHAR(200) --逻辑db名称
DECLARE @LogicalLogName NVARCHAR(200) --逻辑log名称
DECLARE @BackUpFullFileName NVARCHAR(260) --备份文件全名
DECLARE @RESTORESQL NVARCHAR(2000) --备份数据库完整语句
SET @BackUpPath = 'D:\db\'; --备份文件路径
SET @SqlServerPath = 'D:\Software\SQL2014\DB\MSSQL12.MSSQLSERVER\MSSQL\DATA\'; --数据库安装路径(数据文件夹)
--add path \
if (@BackUpPath IS NOT NULL) AND LEN(@BackUpPath)>1 AND (RIGHT(@BackUpPath,1)<>'\')
BEGIN
 SET @BackUpPath=@BackUpPath+'\'
END
IF OBJECT_ID('tempdb..#Temp') IS NOT NULL
    DROP TABLE #Temp
CREATE TABLE #Temp (id INT IDENTITY,a INT,b INT,c INT)
DECLARE @fpath NVARCHAR(3)
SET @fpath=LEFT(@BackUpPath,3)
INSERT #Temp EXEC master..xp_fileexist @fpath
INSERT #Temp EXEC master..xp_fileexist @BackUpPath
--如果指定盘符有误不存在,则返回错误提示:
IF EXISTS(SELECT 1 FROM #Temp WHERE id=1 AND c=0)
BEGIN
    PRINT CHAR(10) + N'备份文件路径的盘符不存在,请重新输入!'
	GOTO ExitFLag
END
--如果不存在指定的文件夹,则创建:
ELSE IF EXISTS(SELECT 1 FROM #Temp WHERE b=0 AND id=2)
BEGIN
   PRINT CHAR(10) + N'备份文件路径不存在,请重新输入!'
   GOTO ExitFLag
END
IF OBJECT_ID('tempdb..#Dir') IS NOT NULL
    DROP TABLE #Dir
CREATE TABLE #Dir  
(  
     BackDBFileName NVARCHAR(100) ,DEPTH INT ,[File] INT  
)
IF OBJECT_ID('tempdb..#FileListInfo') IS NOT NULL
    DROP TABLE #FileListInfo
CREATE TABLE #FileListInfo
(
	LogicalName              NVARCHAR(128) NULL,
	PhysicalName             NVARCHAR(260) NULL,
	TYPE                     CHAR(1) NULL,
	FileGroupName            NVARCHAR(128) NULL,
	FileSize                 BIGINT NULL,
	MAXSIZE                  BIGINT NULL,
	FileId                   BIGINT,
	CreateLSN                NUMERIC(25, 0),
	DropLSN                  NUMERIC(25, 0) NULL,
	UniqueID                 UNIQUEIDENTIFIER,
	ReadOnlyLSN              NUMERIC(25, 0) NULL,
	ReadWriteLSN             NUMERIC(25, 0) NULL,
	BackupSizeInBytes        BIGINT,
	SourceBlockSize          INT,
	FileGroupID              INT,
	LogGroupGUID             UNIQUEIDENTIFIER NULL,
	DifferentialBaseLSN      NUMERIC(25, 0) NULL,
	DifferentialBaseGUID     UNIQUEIDENTIFIER,
	IsReadOnly               BIT,
	IsPresent                BIT,
	TDEThumbprint            BIT
)
 
INSERT INTO #Dir EXEC master..xp_dirtree @BackUpPath,1,1
 
DELETE FROM #Dir WHERE CHARINDEX('.bak', BackDBFileName)=0
IF NOT EXISTS (SELECT TOP 1 1 FROM #Dir)
BEGIN
   PRINT CHAR(10) + N'在提供的路径下没有找到合符要求的备份文件'    
   Goto ExitFLag
 END
 
 PRINT N'开始还原所有数据库'
DECLARE db_file Cursor Local Static Read_Only Forward_Only
FOR
SELECT BackDBFileName from #Dir
 
OPEN db_file
FETCH NEXT FROM db_file INTO @BackUpFileName
WHILE @@FETCH_STATUS=0
 BEGIN
  --Restore DataBase
  SET @BackUpFullFileName=@BackUpPath+@BackUpFileName
  SET @DbName = REPLACE(@BackUpFileName,'.bak','')
  DELETE FROM #FileListInfo
  INSERT INTO #FileListInfo
    EXEC ('RESTORE FILELISTONLY FROM DISK=''' + @BackUpFullFileName + '''')
	SET @LogicalDbName=''
	SELECT @LogicalDbName = LogicalName FROM   #FileListInfo WHERE [TYPE]= 'D'  --数据库文件  
	SET @LogicalLogName=''
    SELECT @LogicalLogName = LogicalName FROM   #FileListInfo WHERE [TYPE]= 'L' --日志文件
	IF (@LogicalDbName IS NULL OR @LogicalDbName = '')  
   SET @LogicalDbName = @DbName
    IF (@LogicalLogName IS NULL OR @LogicalLogName = '')  
   SET @LogicalLogName = @DbName + '_log'
  SET @RESTORESQL = '  
  IF EXISTS (SELECT * FROM master.dbo.sysdatabases WHERE [name]='''+@DbName+''')
  BEGIN
  EXEC msdb.dbo.sp_delete_database_backuphistory @database_name = N'''+@DbName+'''  
  USE [master]  
  DROP DATABASE ['+@DbName +']  
  END
  RESTORE DATABASE '+@DbName+' FROM DISK = '''+@BackUpFullFileName+'''  
  WITH MOVE '''+@LogicalDbName+''' TO '''+@SqlServerPath+@DbName+'.mdf''
 ,MOVE '''+@LogicalLogName+''' TO '''+@SqlServerPath+@DbName+'_log.ldf'' '
   PRINT @RESTORESQL
   EXECUTE  sp_executesql @RESTORESQL
  FETCH NEXT FROM db_file INTO @BackUpFileName
 END
CLOSE db_file
DEALLOCATE db_file
PRINT N'
所有数据库还原完成'
ExitFLag:
----临时表删除--------
IF (OBJECT_ID('tempdb..#Temp') IS NOT NULL)  
  DROP TABLE #Temp  
IF OBJECT_ID('tempdb..#Dir') IS NOT NULL
    DROP TABLE #Dir
IF OBJECT_ID('tempdb..#FileListInfo') IS NOT NULL
    DROP TABLE #FileListInfo

SqlServer数据库硬盘空间释放

我们在使用sqlserver操作数据的时候,会生成Ldf的日志文件和Mdf数据文件,久而久之,会让硬盘可用空间变小,那么时间长了,我们就需要清除一些日志文件和压缩Mdf数据文件,释放出一些硬盘可用空间

注意:清除数据库Ldf日志文件,将会使数据库之前的操作变得不可逆,Ldf文件有助于我们查找之前执行的脚本,或者生成逆向脚本还原数据库。具体教程将后续说明

压缩数据库Ldf文件

打开数据库文件所在位置,找到需要压缩的Ldf文件,如:我们觉得MY_RelationMgmt_log.ldf文件过大,需要压缩执行以下Sql脚本即可。

USE [master]
GO
ALTER DATABASE MY_RelationMgmt SET RECOVERY SIMPLE WITH NO_WAIT
GO
ALTER DATABASE MY_RelationMgmt SET RECOVERY SIMPLE --先进入简单用户模式
GO
USE [MY_RelationMgmt]
GO
DBCC SHRINKFILE (N'MY_RelationMgmt_Log' , 2, TRUNCATEONLY)
GO

再三说明:此脚本一但执行,将无法查询定位以及回滚之前的操作数据库记录

压缩数据库Mdf文件

打开数据库文件所在位置,找到需要压缩的mdf文件,如:我们觉得MY_RelationMgmt_log.mdf文件过大,需要压缩

因为mdf是数据库数据文件,我们得先查看该数据库当前的每个库表硬盘使用情况

先执行以下sql

use [MY_RelationMgmt]
IF OBJECT_ID('tempdb..#TablesSizes') IS NOT NULL
    DROP TABLE #TablesSizes
CREATE TABLE #TablesSizes
    (
      TableName sysname ,
      Rows BIGINT ,
      reserved VARCHAR(100) ,
      data VARCHAR(100) ,
      index_size VARCHAR(100) ,
      unused VARCHAR(100)
    )
DECLARE @sql VARCHAR(MAX)
SELECT  @sql = COALESCE(@sql, '') + '
INSERT INTO #TablesSizes execute sp_spaceused ''' + QUOTENAME(TABLE_SCHEMA,
                                                              '[]') + '.'
        + QUOTENAME(Table_Name, '[]') + ''''
FROM    INFORMATION_SCHEMA.TABLES
WHERE   TABLE_TYPE = 'BASE TABLE'
PRINT ( @SQL )
EXECUTE (@SQL)
SELECT  *
FROM    #TablesSizes
ORDER BY Rows DESC

看下执行结果,这时候,我们可以看到,每个表的使用情况,比如,我们这2张备份表实际上已经不在使用了,我们可以删除,这时候,我们可以先进行drop table或者Delete Row操作

删除多余的表和数据行以后,在左侧资源管理器选中对应数据库,右键——Tasks——Shrink——DateBase———-

我们看到出现收缩后的库,占当前的比例了,点击OK,完成收缩

SQL SERVER 批量备份所有数据库

有时候,我们希望一次性备份指定的几个SQL SERVER数据库文件,以下有个简单的SQL可以实现

可以自己设定Where的条件,批量备份数据库的sql脚本,可以自行设置备份目录,如果目录不存在会自动创建该目录

(如果脚本复制到查询分析器有红线,不用怕,依旧可以执行)

USE [master]
DECLARE @backupfile NVARCHAR(1024)  
DECLARE @backdesc NVARCHAR(1024)  
DECLARE @filename NVARCHAR(1024)  
DECLARE @path NVARCHAR(1024)  
DECLARE @dbname SYSNAME
DECLARE @extension_name NVARCHAR(50)
SET @path = N'D:\DBBackup\';   -- 此处是服务器的备份文件输出路径
SET @extension_name = N'.bak';
IF (OBJECT_ID('tempdb..#Temp') IS NOT NULL)  
  DROP TABLE #Temp  
CREATE TABLE #Temp (id INT IDENTITY,a INT,b INT,c INT)
DECLARE @fpath NVARCHAR(3)
SET @fpath=LEFT(@path,3)
INSERT #Temp EXEC master..xp_fileexist @fpath
INSERT #Temp EXEC master..xp_fileexist @path
--如果指定盘符有误不存在,则返回错误提示:
IF EXISTS(SELECT 1 FROM #Temp WHERE id=1 AND c=0)
BEGIN
    PRINT CHAR(10) + N'输入的盘符不存在,请重新输入!'
	----临时表删除--------
IF (OBJECT_ID('tempdb..#Temp') IS NOT NULL)  
BEGIN  
  DROP TABLE #Temp  
END
RETURN
END
--如果不存在指定的文件夹,则创建:
ELSE IF EXISTS(SELECT 1 FROM #Temp WHERE b=0 AND id=2)
BEGIN
PRINT CHAR(10) + N'正在创建目录'
EXEC sp_configure 'show advanced options',1
reconfigure
EXEC sp_configure 'xp_cmdshell',1
reconfigure
    DECLARE @mddir NVARCHAR(100)
    SET @mddir='md '+@path
    EXEC master..xp_cmdshell @mddir
	PRINT CHAR(10) + N'创建目录完成'
END
----临时表删除--------
IF (OBJECT_ID('tempdb..#Temp') IS NOT NULL)  
BEGIN  
  DROP TABLE #Temp  
END
--备份
PRINT CHAR(10) + N'开始备份所有数据库'
DECLARE tmp_Cur CURSOR  
FOR  
    SELECT  name  
    FROM    sys.databases  
    WHERE ([name] LIKE '%MGMT' )  -- 此处条件可以自定义,
    ORDER BY Name
 
OPEN tmp_Cur
FETCH NEXT FROM tmp_Cur INTO @dbname;  
WHILE @@FETCH_STATUS = 0    
    BEGIN  
        -- 得到完整目标文件,数据库将备份到这个文件中  
        SET @backupfile = @path + @dbname + @extension_name
        --SELECT  @backupfile  
        SET @backdesc =@dbname + N'-完整 数据库 备份'  
 
        -- 开始备份, COMPRESSION 参数表示压缩,可节省磁盘空间
  PRINT CHAR(10) + N'开始备份 '+@dbname
  PRINT CHAR(10)
        BACKUP DATABASE @dbname TO DISK = @backupfile WITH NOFORMAT, NOINIT,  NAME = @backdesc, SKIP, NOREWIND, NOUNLOAD,  STATS = 10, COMPRESSION  
        PRINT CHAR(10) + @dbname + N' 备份完成 '
        FETCH NEXT FROM tmp_Cur INTO @dbname  
    END  
CLOSE tmp_Cur
DEALLOCATE tmp_Cur
PRINT CHAR(10) + N'所有数据库备份完成'

执行完毕后,就可以在服务器的D:\DBBackup路径上找到这些BAK文件

MySQL8 新特性和常用查询优化

1:默认数据引擎改变为InnoDB

Mysql8之前的版本,默认引擎为MyISAM(主要的非事务处理存储引擎),从Mysql8开始,数据库默认引擎为InnoDB(支持事务、分布式、事务部分回滚、行级锁、外键)

2:默认字符集改变为utf8mb4

Mysql8之前的版本,默认字符集为lation1,从Mysql8开始,数据库默认编码改为utf8mb4

3:新增设置系统变量参数(Persist),全局变量的持久化,如下:

show [global|session] variables like '%time_zone%'; 
 set [global|session|persist] time_zone='+8:00';  
 flush privileges; # 立即生效

4:自增变量的持久化

 Create table test1(
 id int auto_increment primary key,
 Val int
 );
 Insert into test1(val) values (1);
 Delete from table where id=1;
 -- 重启数据库
 Insert into test1(val) values (1);
 Select * from test1
 -- 发现id变成了2,但如果是MySQL5的版本,则id会是1
 

5:新增窗口函数

窗口函数类似sum(),count()那样的聚合函数,但是它不会将多行合并,而是将结果多行返回,也就是说,窗口函数是不需要Group By的,以下是几个简单的例子

 select *,sum(count) over() as totalcount from Orders;
 
 select *,count/(sum(count) over()) as totalcount from Orders;

6:新增通用表达式

通用表达试简称CTE,CTE是命名的临时结果集,作用范围是当前语句,CTE可以理解成一个可以复用的子查询,CTE可以引用其他CTE,但是子查询不能引用其他子查询 例如我们在8.0之前的sql,只能使用子查询获取类别名称

 Select g.*,(select name from category where id=g.cat_id)  cat_name from goods g;

但是在8.0之后,我们可以用CTE的方式

 With cte as ( select * from category)    
 Select g.*,(select cte.name from cte where cte.id=g.cat_id)  cat_name from goods g;

相比子查询,cte的效率会更高,因为非递归的cte只会查询一次并可以重复使用。
我们也可以使用cte引用其它cte,达到查询目的,查询例子如下

 With cte1 as ( select * from category),
 cte2 as (select g.*,cte1. name  cat_name  from goods g left join cte1 on g.cat_id=cte1.id) 
 select * from cte2

7:通用表达式CET递归神器

递归cte是特殊的cte,必须以WITH RECURSIVE开头,递归子查询包括两部分,SEED查询和RECURSIVE查询,中间由union[all]分隔, SEED查询只会执行1次,以创建初始数据集, RECURSIVE查询会重复执行,直到无法满足语句条件为止。

With RECURSIVE cte as (
 select 1 n     -- SEED查询
 union all 
 Select n+1 n from cte where n<8)  -- RECURSIVE查询
 Select * from cte;

以下是2个常用场景

场景1:递归查询指定节点的所有后代

 set @customer_id=2; -- 当前节点
 WITH RECURSIVE cte AS
 (
 SELECT 
 a.customer_id, a.inviter_id,
 cast(a.inviter_id as char(255)) path
 FROM t_customer_relation a WHERE a.customer_id=@customer_id
 UNION ALL
 SELECT
 k.customer_id,k.inviter_id,
 concat(cte.path,',', k.inviter_id) path
 FROM t_customer_relation k 
 INNER JOIN cte ON cte.customer_id = k.inviter_id
 )
 SELECT cte.customer_id,cte.inviter_id,cte.path  FROM cte 
 -- left join t_customer d  on cte.customer_id=d.id
 

场景2:根据当前节点,查询自己的祖宗

set @customer_id =29 ; -- 当前节点
 WITH RECURSIVE cte AS(
     SELECT
     customer_id, 
     inviter_id, 
     convert(inviter_id , char(255)) path 
     FROM t_customer_relation WHERE customer_id = @customer_id 
     UNION ALL
     SELECT 
     c.customer_id, 
     c.inviter_id, 
     concat(cte.path,',', c.inviter_id) path 
     FROM t_customer_relation c, cte WHERE c.customer_id= cte.inviter_id
 )SELECT * FROM cte;

8:支持json类型

Mysql是关系数据库,我们如果再Mysql8前如果有此类需求,一般用Blob类型存取。但是存在以下 缺点:

1.无法保证json正确性

2.json的二操作加工需要代码处理

3.读取json的某个字段,必须从数据库读出字段所有内容

4.无法在json上的某个字段建索引

现在,可以试试在表里使用json类型字段。如下:

Create table tb(
 jsdata  json
 );
 Insert into table(’{”key”:”123”}’);

值得注意的是,key的长度不能超过2个字节(65535)。Mysql8.0提供了很多操作json的函数,包括条件查询,具体可以参考官方文档说明

9:其他新特性

a:加密函数(md5(str),sha (str),sha2 (str,hash_length))

b:GROUP BY 不再隐式排序

c:DLL的原子化(drop table table1,table2;如果table2不存在,那table1将不会删除)

d:支持降序索引

e:统计直方图

f:支持表空间加密

g:支持不可见索引(相对于enable,哪怕隐藏时依然和正常索引一样实时更新,查询不再走)

h:跳过锁等待,sql如下:

select * from table where id=1 for update nowait; --有锁就报错)
select * from table where id=1 for update skip locked; --有锁就不理)

MySql时间格式函数

以下命令为MySql的常用时间函数,可以在编写服务端时,为时间运算和分组提供便利,具体函数如下

select now() `当前时间`,
 unix_timestamp(now()) `时间戳(秒)`,
 from_unixtime(unix_timestamp(now())) `时间戳->时间`,
 concat(date_format(utc_date(),'%Y-%m-%d'),date_format(utc_time(),' %H:%i:%s')) `格林尼治时间`,
 month(now()) `月份`,
 monthname(now()) `月份`,
 dayname(now()) `星期`,
 dayofweek(now()) `对应一周中的索引(1周日 2周一 …… 7周六)`,
 weekday(now()) `日期对应的周索引(0周一 1周二 …… 6周日)`,
 week('2021-01-02',0) `计算时间是一年中的第几周`,   --  一周的第一天(日) 范围(0~53)  本年度中有一个周日
 week('2021-01-02',2) `计算时间是一年中的第几周`,   --  一周的第一天(日) 范围(1~53)  本年度中有一个周日
 week('2021-01-02',1) `计算时间是一年中的第几周`,   --  一周的第一天(一) 范围(0~53)  本年度中有3天以上
 week('2021-01-02',3) `计算时间是一年中的第几周`,   --  一周的第一天(一) 范围(1~53)  本年度中有3天以上
 week('2021-01-02',4) `计算时间是一年中的第几周`,   --  一周的第一天(日) 范围(0~53)  本年度中有3天以上
 week('2021-01-02',6) `计算时间是一年中的第几周`,   --  一周的第一天(日) 范围(1~53)  本年度中有3天以上
 week('2021-01-02',5) `计算时间是一年中的第几周`,   --  一周的第一天(一) 范围(0~53)  本年度中有一个周一
 week('2021-01-02',7) `计算时间是一年中的第几周`,   --  一周的第一天(一) 范围(1~53)  本年度中有一个周一
 dayofyear(now()) `一年当中的第几天`,
 date_Add(now(),interval 1 day) `新增一天`,
 date_format(now(),'%Y-%m-%d %H:%i:%s') `时间格式化`

创建MYSQL的定时任务

自MySQL5.1.6起,增加了一个非常有特色的功能-事件调度器(Event Scheduler),可以用做定时执行某些特定任务(例如:删除记录、对数据进行汇总、数据备份等等)。更值得一提的是MySQL的事件调度器可以精确到每秒钟执行一个任务,而操作系统的计划任务(如:Linux的cron或Windows下的任务计划)只能精确到每分钟执行一次。对于一些对数据实时性要求比较高的应用(例如:股票、赔率、比分等)就非常适合。

1、在使用这个功能之前必须确保event_scheduler已开启,可执行

 SET GLOBAL event_scheduler = 1;

2、要查看当前是否已开启事件调度器,可执行如下SQL:

 SHOW VARIABLES LIKE 'event_scheduler';

注:以下为其他常用命令

 ALTER EVENT eventName ON COMPLETION PRESERVE DISABLE;  --关闭事件任务
 ALTER EVENT eventName ON COMPLETION PRESERVE ENABLE;   --开启事件任务
 SHOW EVENTS;                                          --查看事件任务

具体创建语法如下

CREATE EVENT [IFNOT EXISTS] event_name
 ONSCHEDULE schedule
 [ONCOMPLETION [NOT] PRESERVE]
 [ENABLE | DISABLE]
 [COMMENT 'comment']
 DO sql_statement;

schedule:
AT TIMESTAMP [+ INTERVAL INTERVAL]
| EVERY INTERVAL [STARTS TIMESTAMP] [ENDS TIMESTAMP]
  
INTERVAL:
quantity {YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE |
WEEK | SECOND | YEAR_MONTH | DAY_HOUR | DAY_MINUTE |
DAY_SECOND | HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND}

首先来看一个简单的例子来演示每秒插入一条记录到数据表 

CREATE TABLE aaa(timeline TIMESTAMP);
 CREATE EVENT e_test_insert
 ON SCHEDULE EVERY 1 SECOND
 DO INSERT aaa VALUE(CURRENT_TIMESTAMP);

等待3秒之后,再执行查询看看,可以看到aaa表会有3条数据
再来看看修改他的语法

ALTER EVENT event_name
 [ONSCHEDULE schedule]
 [RENAME TOnew_event_name]
 [ON COMPLETION [NOT] PRESERVE]
 [COMMENT 'comment']
 [ENABLE | DISABLE]
 [DO sql_statement]

以下是几个简单例子

ALTER EVENT e_test DISABLE;   -- 临时关闭事件
 ALTER EVENT e_test ENABLE;   -- 开启事件  
 ALTER EVENT e_test ON SCHEDULE EVERY 5 DAY;  -- 将任务改为5天执行一次:

最后是删除事件语法

DROP EVENT [IF EXISTS] event_name

SQL Server 阻止了对组件“Ad Hoc Distributed Queries”的 STATEMENT“OpenRowset/OpenDatasource”的访问

当SQL Server阻止对组件”Ad Hoc Distributed Queries”的访问时,这是由于服务器的安全配置将此组件关闭所致。”Ad Hoc Distributed Queries”用于允许在SQL Server中执行动态查询并访问其他数据库服务器上的数据。
要启用”Ad Hoc Distributed Queries”,需要使用sp_configure系统存储过程进行配置。以下是一些步骤来启用”Ad Hoc Distributed Queries”:

1.使用sa或具有sysadmin角色的登录名连接到SQL Server。
2.打开SQL Server Management Studio (SSMS)并连接到相应的SQL Server实例。
3.执行以下命令以启用”Ad Hoc Distributed Queries”:

sp_configure 'show advanced options', 1;
 GO
 RECONFIGURE;
 GO
 sp_configure 'Ad Hoc Distributed Queries', 1;
 GO
 RECONFIGURE;
 GO

第一条命令允许显示高级选项,第三条命令启用”Ad Hoc Distributed Queries”选项。RECONFIGURE命令用于应用配置更改。
请注意,启用”Ad Hoc Distributed Queries”可能会存在一些安全风险,因此建议在启用之前评估潜在的风险并采取适当的安全措施。此外,确保只有授权人员可以执行此操作,并且在启用后密切监视使用该功能的查询。
有关更多详细信息和指导,请参考SQL Server的官方文档、SQL Server联机丛书或与数据库管理员进行进一步的讨论