I am trying to change a stored procedure in our SQL environment which is used to create backup jobs remotely. Below is the procedure
/****** 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
The job created is created with 3 retries, so if backup fails it retires and then backs up all the database again irrespective where it failed. I am trying to change the procedure so that when the job fails it runs backup for databases which have failed. I have written below code to replace where it backups up database.
*@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
When I make this changes from job step , query parses fine and job runs fine. But when i put this in this procedure and try to create jobs remotely it fails with syntax error. As it is dynamic sql it does not provide me any clue where is the syntax error.
Would be great if someone can spot it.
Regards, Sid