SQL Server备份数据库清除过期备份的存储过程






  采用SQL Server自带的数据库维护向导,需手动创建数据库备份和清理备份工作任务,不方便对数据库名称、保存路径及过期时间进行动态设置,因此笔者创建存储过程,可以设置数据库名、存档路径以及过期月份(如按天、周者自行修改),然后在新建工作中的步骤执行该存储过程即可。在新建工作可自行设定执行时间和周期,实现数据库按周期备份和清理。



备份数据名称格式:[数据库名称]_年_月_日_时_分_秒.bak



其中年为四位数字,其它月日时分秒均为两位数字



将计划工作创建后可生成创建代码,另建存储过程,将创建工作代码纳入存储过程中,方便后台系统调用灵活部署和调用。



 



主要步骤及难点:



1、数据库备份名称日期时间格式的生成SQL语句:



  

set @dateTime = REPLACE(CONVERT(varchar(10), GETDATE(), 120),'-','_')+'_'+  +REPLACE(CONVERT(varchar(10), GETDATE(), 8),':','_');
 
    
  set @File=@BackupDir+@DatabaseName+'_'+@dateTime+'.Bak';


2、备份数据库SQL语句:



 

Backup database @DatabaseName to Disk=@File  With NOINIT ,NOUNLOAD,NOSKIP,STATS=10,NOFORMAT


3、启动xp_cmdshell  存储过程中不允许有Use语句,因此才有SQL语句字符串执行:


set @sql='
 
    
     use msdb 
 
    
     exec sp_configure ''show advanced options'', 1;
 
    
     reconfigure;
 
    
     exec sp_configure ''xp_cmdshell'',1;
 
    
     reconfigure; '
 
    
   exec(@sql)
 
    
 
     4、定义表变量并将备份目录中的文件保存到表变量中,SQL语句:  
    
 
    
   DECLARE @Tab table (subdirectory nvarchar(Max),depth smallint,[file] bit)  
 
     
   insert @Tab exec master..xp_dirtree @BackupDir,1,1
 
    

      5、游标遍历表变量中文件,根据文件名所含的时间信息判断是否过期,游标SQL语句: 
    
 
    
   declare my_cursor cursor for (select subdirectory from @Tab)
 
    
      --打开游标--
 
    
      open my_cursor
 
    
      --开始循环游标变量--
 
    
      fetch next from my_cursor into @subdirectory
 
    
      while @@FETCH_STATUS = 0     
 
    
          begin  
 
    

            --根据文件名所含的时间信息判断是否过期,过期则采用xp_cmdshell删除 
    
 
    

              ...... 
    
 
    

        
    
 
    
      fetch next from my_cursor into @subdirectory
 
     
         end    
 
     
  close my_cursor   
 
     
  deallocate my_cursor    
 
    
 
 
    
 6、判断是否过期需获取文件名中的时间,采用表值函数Get_StrArrayStrOfIndex(见后),SQL语句: 
    
 
    
 set @Year= dbo.Get_StrArrayStrOfIndex(@subdirectory,'_',2)  
 
    
   set @Month= dbo.Get_StrArrayStrOfIndex(@subdirectory,'_',3)
 
    
   set @Day= dbo.Get_StrArrayStrOfIndex(@subdirectory,'_',4) 
 
    
   set  @MyDatetime=convert(varchar(4),@Year) +'-'+convert(varchar(2),@Month) +'-'+convert(varchar(2),@Day)
 
    

      7、判断是否过期,过期采用xp_cmdshell删除,SQL语句: 
    
 
    
if(DATEDIFF ( MONTH,@MyDatetime,GETDATE () )>@InvalidMonth)
 
    
   Begin  
 
     
     set @sql='exec master.dbo.xp_cmdshell ''del '+@File+''''
 
     
     exec( @sql)
 
     
   End



存储过程如下:



1 SET ANSI_NULLS ON
 2 GO
 3 SET QUOTED_IDENTIFIER ON
 4 GO
 5 -- =============================================
 6 -- Author:        <jcstone,,Name>
 7 -- Create date: <Create Date,2018-8-13,>
 8 -- Description:    <Description,数据库备份和清除工具,@BackupDir备份目录(如'E:\DBBackup\'),@DatabaseName备份数据库,@InvalidMonth清除备份所距离今天的月份数>
 9 -- =============================================
10 Create PROCEDURE [dbo].[P_ZTool_BackupAndClearDatabase] 
11      @BackupDir nvarchar(300) ,
12      @DatabaseName nvarchar(100) ,
13      @InvalidMonth int
14 AS
15 BEGIN 
16  
17     --备份数据库
18     declare @sql varchar(200);
19     
20     declare @File  NVARCHAR(100);
21     DECLARE @dateTime NVARCHAR(20);
22     set @dateTime = REPLACE(CONVERT(varchar(10), GETDATE(), 120),'-','_')+'_'+  +REPLACE(CONVERT(varchar(10), GETDATE(), 8),':','_');
23     set @File=@BackupDir+@DatabaseName+'_'+@dateTime+'.Bak';
24      
25     Backup database @DatabaseName to Disk=@File  With NOINIT ,NOUNLOAD,NOSKIP,STATS=10,NOFORMAT
26      
27     
28     --启动xp_cmdshell 
29     set @sql='
30     use msdb 
31     exec sp_configure ''show advanced options'', 1;
32     reconfigure;
33     exec sp_configure ''xp_cmdshell'',1;
34     reconfigure; '
35     exec(@sql)
36   
37   
38        --将文件夹下文件和子文件夹存入表变量@Tab
39     DECLARE @Tab table (subdirectory nvarchar(Max),depth smallint,[file] bit)  
40     insert @Tab exec master..xp_dirtree @BackupDir,1,1
41      
42     --定义文件名中时间临时表(便于重置清除临时表数据),在循环中重复赋值后再清除
43     declare @MyDatetime datetime
44     declare @Year int ,@Month int , @Day int 
45      
46     
47     --循环遍历表变量中的文件,比对日期是否超过2个月,超过则删除
48     declare @subdirectory nvarchar(200)
49     declare @delFile nvarchar(200)
50     declare my_cursor cursor for (select subdirectory from @Tab)
51     --打开游标--
52     open my_cursor
53     --开始循环游标变量--
54     fetch next from my_cursor into @subdirectory
55     while @@FETCH_STATUS = 0     
56         begin  
57              set @Year= dbo.Get_StrArrayStrOfIndex(@subdirectory,'_',2)  
58             set @Month= dbo.Get_StrArrayStrOfIndex(@subdirectory,'_',3)
59             set @Day= dbo.Get_StrArrayStrOfIndex(@subdirectory,'_',4) 
60             set  @MyDatetime=convert(varchar(4),@Year) +'-'+convert(varchar(2),@Month) +'-'+convert(varchar(2),@Day)
61             
62             set @File=@BackupDir+@subdirectory
63             
64             if(DATEDIFF ( MONTH,@MyDatetime,GETDATE () )>@InvalidMonth)
65             Begin 
66                 --select @MyDatetime,'删除文件:'+@File
67                 set @sql='exec master.dbo.xp_cmdshell ''del '+@File+''''
68                 exec( @sql)
69             End  
70             else
71             --Begin 
72             --    --select @MyDatetime ,'不删除文件:'+@subdirectory 
73             --End  
74             fetch next from my_cursor into @subdirectory
75         end    
76     close my_cursor   
77     deallocate my_cursor    
78 
79 END



其中表值函数Get_StrArrayStrOfIndex的代码如下:



1 -- =============================================
 2 -- Author:        <Author,jcstone,Name>
 3 -- Create date: <Create Date,2013-1-28,>
 4 -- Description:    <Description,字符串分解为int表值,>
 5 -- =============================================
 6  
 7 Create function [dbo].[Get_StrArrayStrOfIndex]
 8 (
 9   @str varchar(5000),  --要分割的字符串
10   @split varchar(10),  --分隔符号
11   @index int --取第几个元素
12 )
13 returns varchar(200)
14 as
15 begin
16   declare @location int
17   declare @start int
18   declare @next int
19   declare @seed int
20 
21   set @str=ltrim(rtrim(@str))
22   set @start=1
23   set @next=1
24   set @seed=len(@split)
25   
26   set @location=charindex(@split,@str)
27   while @location<>0 and @index>@next
28   begin
29     set @start=@location+@seed
30     set @location=charindex(@split,@str,@start)
31     set @next=@next+1
32   end
33   if @location =0 select @location =len(@str)+1 
34   return substring(@str,@start,@location-@start)
35 end