2016-06-08 47 views
2

我試圖改變我們的SQL環境中用於遠程創建備份作業的存儲過程。下面是程序動態查詢語法錯誤

/****** Object: StoredProcedure [dbo].[CreateBackupJobGroupBFull] Script Date: 8/06/2016 3:18:25 PM ******/ 
SET ANSI_NULLS ON 
GO 

SET QUOTED_IDENTIFIER ON 
GO 


ALTER PROCEDURE [dbo].[CreateBackupJobGroupAFull] 
(@servername nvarchar(100)) 
AS 

declare @commandstr nvarchar(max) 
DECLARE @SQL nvarchar(4000) 
DECLARE @TableExists bit 
DECLARE @recp nvarchar(100) 
DECLARE @error_msg varchar(300) 
declare @groupAfull nvarchar(150) 
declare @schedulestr nvarchar(150) 
DECLARE @pripathstr VARCHAR(1256) 
DECLARE @secpathstr VARCHAR(1256) 
declare @defaultscheduleStart varchar(30) 
declare @gstr varchar(5) 
declare @g varchar(1) 

set @groupAfull = 'DBABackupJobGroupA_Full' 
set @recp = '**************' 
set @defaultscheduleStart = '230000' 
set @gstr = '_GA_F' 
set @g = 'A' 

SET @SQL = 'SELECT @TableExists = CASE WHEN TableExists = 0 THEN 0 ELSE 1 END 
      FROM OPENQUERY(' + QUOTENAME(@servername) 
      + ', ''SELECT TableExists = COUNT(*) 
        from msdb.dbo.sysjobs 
        WHERE name = '''' + @groupAfull + '''''');'; 

begin try 
         EXECUTE sp_executesql @SQL, N'@TableExists BIT OUTPUT', @TableExists OUT; 

END TRY 
BEGIN CATCH 
         print 'error message is:' 
         print error_message() 
         set @error_msg='Error occurred when executing CreatBackupJob against server ' + @ServerName + '. Failed to check control table locally. The error message is: ' + error_message() 

         EXEC msdb.dbo.sp_send_dbmail 
         @profile_name = 'Internal mail', 
         @recipients = @recp, 
         @body = @error_msg , 
         @subject = 'Error occurred on reporting server' ; 
END CATCH      

IF (@TableExists = 0) 
BEGIN 

      --add new job for the instance 
      set @sql = 'if not exists (select * from [' + @ServerName + '].msdb.dbo.sysjobs where name = ''' + @groupAfull + ''') 
      BEGIN 
      EXEC [' + @ServerName + '].msdb.dbo.sp_add_job 
      @job_name = ''' + @groupAfull + ''', 
      @enabled = 1, 
      @description = N''DBA backup job. DO NOT REMOVE. V1.5 (2015-06-16)'', 
      @owner_login_name = N''sa'' 
      EXEC [' + @ServerName + '].msdb.dbo.sp_add_jobserver 
      @job_name = ''' + @groupAfull + ''', 
      @server_name = ''(local)'' 
      end 
      ' 

      begin try 
         EXEC sp_executeSQL @sql 

      END TRY 
      BEGIN CATCH 
         print 'error message is:' 
         print error_message() 
         set @error_msg='Error occurred when executing CreatBackupJob against server ' + @ServerName + '. Failed to create new job'+ @groupAfull +'. The error message is: ' + error_message() 

         EXEC msdb.dbo.sp_send_dbmail 
         @profile_name = 'Internal mail', 
         @recipients = @recp, 
         @body = @error_msg , 
         @subject = 'Error occurred on reporting server' ; 
      END CATCH  

SET @pripathstr = (SELECT Top 1 [PrimDestinationfull] FROM [SQLADMIN].[dbo].[BackupDestination]) 
SET @secpathstr = (SELECT Top 1 [SecDestinationfull] FROM [SQLADMIN].[dbo].[BackupDestination]) 

      --add job step 1 'test' 
      set @commandstr = ' 
DECLARE @dbname VARCHAR(150) -- database name 
DECLARE @pripath VARCHAR(1256) -- path for backup files 
DECLARE @secpath VARCHAR(1256) -- path for backup files 
DECLARE @path VARCHAR(1256) -- path for backup files 
DECLARE @fileName VARCHAR(1256) -- filename for backup 
DECLARE @fileDate VARCHAR(40) -- used for file name 
DECLARE @DBGROUP varchar(1) 
DECLARE @filecount int 
DECLARE @lastbackuptime datetime 

SET @DBGROUP = ''''' + @g + ''''' 

IF not EXISTS (SELECT [name] FROM msdb.sys.tables WHERE [name] = ''''DBBackupControlTbl'''' ) 
    begin 
     raiserror(''''Control table not found!'''', 20, -1) with log 
     return 
    end 
else 

    if (select count(*) from msdb.dbo.DBBackupControlTbl where BackupGroup = @DBGROUP) > 0 

    -- specify database backup directory 
    SET @pripath = ''''' + @pripathstr + ''''' 
    SET @secpath = ''''' + @secpathstr + ''''' 


    if object_id(''''tempdb.dbo.#fileExist'''') is not null 
      drop table #fileExist 
    create table #fileExist (
      fileExists int, 
      fileIsDir int, 
      parentDirExists int 
     ) 
    insert into #fileExist 
    exec xp_fileexist @pripath 

    if object_id(''''tempdb.dbo.#fileExist2'''') is not null 
      drop table #fileExist2 
    create table #fileExist2 (
      fileExists int, 
      fileIsDir int, 
      parentDirExists int 
     ) 
    insert into #fileExist2 
    exec xp_fileexist @secpath 

    if (select count(*) from #fileExist where fileIsDir = 1) > 0 
     begin 
     set @path = @pripath 
     end 
    ELSE 
     begin 
      if (select count(*) from #fileExist2 where fileIsDir = 1) > 0 
      begin 
       set @path = @secpath 
      end 
     ELSE 
      begin 
       raiserror(''''None of the backup directory can be accessed at the moment!'''', 20, -1) with log 
       return 
      end 
     end 

    set @filecount = 999 
    while @filecount >= 15 
    begin 
     IF OBJECT_ID(''''tempdb..#DirectoryTree'''') IS NOT NULL 
       DROP TABLE #DirectoryTree; 

     CREATE TABLE #DirectoryTree (
       id int IDENTITY(1,1) 
       ,subdirectory nvarchar(512) 
       ,depth int 
       ,isfile bit); 

     INSERT #DirectoryTree (subdirectory,depth,isfile) 
     EXEC master.sys.xp_dirtree @path,1,1; 

     select @filecount = COUNT(*) FROM #DirectoryTree 
     WHERE isfile = 1 AND RIGHT(subdirectory,4) = ''''.sts'''' 

     if @filecount >= 15 
      begin 
      print ''''Wait for status file to be cleared.'''' 
      waitfor delay ''''00:00:10'''' 
      end 
     else 
      begin 
      print ''''Backing up now.'''' 

      DECLARE @statusfile AS VARCHAR(150) 
      DECLARE @cmd AS VARCHAR(150) 



    -- specify filename format 
    SELECT @fileDate = replace(replace(CONVERT(VARCHAR(40),GETDATE(),120), '''':'''', ''''-''''), '''' '''', ''''T'''') 

    set @statusfile = @path + replace(@@SERVERNAME, ''''\'''', ''''-'''') + ''''_'''' + @fileDate + '''''+ @gstr + ''''' + ''''.STS'''' 
    set @cmd = ''''echo '''' + @filedate + '''' > '''' + @statusfile 
    EXECUTE Master.dbo.xp_CmdShell @Cmd 


    DECLARE db_cursor CURSOR FOR 
    select databasename from msdb.dbo.DBBackupControlTbl where BackupGroup = @DBGROUP 

    OPEN db_cursor 
    FETCH NEXT FROM db_cursor INTO @dbname 

    WHILE @@FETCH_STATUS = 0 
     BEGIN 
     SET @fileName = @path + replace(@@SERVERNAME, ''''\'''', ''''-'''') + ''''_'''' + @dbname + ''''_'''' + @fileDate + '''''+ @gstr + ''''' + ''''.BAK'''' 
     BACKUP DATABASE @dbname TO DISK = @fileName 
     FETCH NEXT FROM db_cursor INTO @dbname 
END 

    CLOSE db_cursor 
    DEALLOCATE db_cursor 

    set @cmd = ''''del '''' + @statusfile 
    EXECUTE Master.dbo.xp_CmdShell @Cmd 

    end 
    continue 
    end 
' 
      print @commandstr 

      set @sql = 'if not exists (select * from [' + @ServerName + '].msdb.dbo.sysjobsteps where step_name = ''' + @groupAfull + ''') 
      BEGIN 
      EXEC [' + @ServerName + '].msdb.dbo.sp_add_jobstep 
      @job_name = ''' + @groupAfull + ''', 
      @step_name = ''' + @groupAfull + ''', 
      @subsystem = N''TSQL'', 
      @command = N''' + @commandstr + ''', 
      @retry_attempts = 3, 
      @retry_interval = 1, 
      @on_success_action = 1 , 
      @on_fail_action= 2; 
      end 
      ' 
      begin try 
         EXEC sp_executeSQL @sql 

      END TRY 
      BEGIN CATCH 
         print 'error message is:' 
         print error_message() 
         set @error_msg='Error occurred when executing CreatBackupJob against server ' + @ServerName + '. Failed to create new job step '+ @groupAfull +'. The error message is: ' + error_message() 

         EXEC msdb.dbo.sp_send_dbmail 
         @profile_name = 'Internal mail', 
         @recipients = @recp, 
         @body = @error_msg , 
         @subject = 'Error occurred on reporting server' ; 
      END CATCH  

      --add the schedule 
      set @schedulestr = @groupAfull + '_Schedule' 
      set @sql = 'if not exists (select * from [' + @ServerName + '].msdb.dbo.sysschedules where name = ''' + @schedulestr + ''') 
      BEGIN 
      EXEC [' + @ServerName + '].msdb.dbo.sp_add_schedule 
      @schedule_name = ''' + @schedulestr + ''', 
      @enabled=1, 
      @freq_type=4, 
      @freq_interval=1, 
      @freq_subday_type=1, 
      @freq_subday_interval=0, 
      @freq_relative_interval=0, 
      @freq_recurrence_factor=1, 
      @active_start_date=20140819, 
      @active_end_date=99991231, 
      @active_start_time= '+ @defaultscheduleStart +', 
      @active_end_time=235959 
      end 
      ' 
      --print @sql 
      begin try 
         EXEC sp_executeSQL @sql 

      END TRY 
      BEGIN CATCH 
         print 'error message is:' 
         print error_message() 
         set @error_msg='Error occurred when executing CreatBackupJob against server ' + @ServerName + '. Failed to create new job schedule '+ @groupAfull +'. The error message is: ' + error_message() 

         EXEC msdb.dbo.sp_send_dbmail 
         @profile_name = 'Internal mail', 
         @recipients = @recp, 
         @body = @error_msg , 
         @subject = 'Error occurred on reporting server' ; 
      END CATCH  

      --attach the schedule 
      set @sql = 'EXEC [' + @ServerName + '].msdb.dbo.sp_attach_schedule 
      @job_name = ''' + @groupAfull + ''', 
      @schedule_name = ''' + @schedulestr + ''' 
      ' 
      begin try 
         EXEC sp_executeSQL @sql 

      END TRY 
      BEGIN CATCH 
         print 'error message is:' 
         print error_message() 
         set @error_msg='Error occurred when executing CreatBackupJob against server ' + @ServerName + '. Failed to attach the schedule to the job '+ @groupAfull +'. The error message is: ' + error_message() 

         EXEC msdb.dbo.sp_send_dbmail 
         @profile_name = 'Internal mail', 
         @recipients = @recp, 
         @body = @error_msg , 
         @subject = 'Error occurred on reporting server' ; 
      END CATCH  
end 
GO 

與3個重創建,因此,如果備份失敗就退休,然後再次無關備份所有的數據庫,在那裏失敗創建工作。我正在嘗試更改該過程,以便在作業失敗時爲運行失敗的數據庫運行備份。我寫了下面的代碼來替換備份數據庫的位置。

*@lastbackuptime is declared 

BEGIN 
    SET @lastbackuptime = (select max(backup_finish_date) from msdb.dbo.backupset where [email protected] and type=''''D'''') 
    if (Select datediff(hour,@lastbackuptime,getdate()))> 18 
     Begin 
      SET @fileName = @path + replace(@@SERVERNAME, ''''\'''', ''''-'''') + ''''_'''' + @dbname + ''''_'''' + @fileDate + '''''+ @gstr + ''''' + ''''.BAK'''' 
      BACKUP DATABASE @dbname TO DISK = @fileName 
     End 
    else 
     Begin 
     Print ''''Backup exists for database '''' 
     End 
    FETCH NEXT FROM db_cursor INTO @dbname 
END 

當我從作業步驟進行此更改時,查詢解析正常並且作業正常運行。但是,當我把這個過程中,並嘗試遠程創建作業失敗,語法錯誤。因爲它是動態的SQL它不提供任何線索在哪裏是語法錯誤。

將是巨大的,如果有人能發現它。

的問候中,「動態SQL不工作」 希德

+3

調試時動態SQL它來執行它之前打印結果字符串的關鍵。長字符串可以通過PRINT命令截斷,因此您需要使用解決方法:http://stackoverflow.com/questions/7850477/how-to-print-varcharmax-using-print-statement。一旦你得到完整的字符串打印檢查它的語法錯誤並運行它。修復動態SQL生成器代碼中的錯誤並沖洗並重復。 – Alex

回答

1

問題類型拿出經常和有時(如你的情況)可能會非常難以回答,因爲我們不能執行您所提供的代碼。

所以這個答案描述調試動態SQL的方法。

  1. 添加PRINT語句來打印被執行之前的動態SQL字符串。當使用PRINT命令時,長字符串可能會被截斷,因此您需要使用解決方法(How to print VARCHAR(MAX) using Print Statement?提供了幾個解決方案)。

  2. 一旦你的整個字符串打印檢查是否有語法錯誤和/或只要運行它。您可以通過將代碼粘貼到新的查詢窗口並運行「解析」(Ctrl + F5)來檢查代碼是否出現語法錯誤。

  3. 一旦動態SQL錯誤識別你需要找到在動態SQL生成的代碼生成此錯誤的地方,解決它。

  4. 重複這個過程,直到沒有剩下的錯誤。