我正在尝试在我们的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 database_name=@dbname 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,所以它没有提供任何线索在哪里是语法错误。
如果有人能发现它会很棒。
此致 SID
答案 0 :(得分:1)
"动态SQL无效的问题"类型经常出现,有时(如你的情况)很难回答,因为我们无法执行你提供的代码。
所以这个答案描述了调试动态SQL的方法。
添加PRINT
语句,以便在执行之前打印动态SQL字符串。使用PRINT
命令时,可以截断长字符串,因此需要使用变通方法(How to print VARCHAR(MAX) using Print Statement?提供了一些解决方案)。
打印完整个字符串后,请检查语法错误和/或运行它。您可以通过将代码粘贴到新的查询窗口并运行" Parse"来检查代码的语法错误。 (按Ctrl + F5)。
识别出动态SQL中的错误后,您需要在动态SQL生成器代码中找到产生此错误的位置并将其修复。
重复此过程,直到没有错误。