I have been working to replicate the Box feature of AutoSys. I came across a solution shown here (https://dba.stackexchange.com/a/161658), that works very, very well. I started to add to it, checking outcome, and added handling of another ETL solution we use.
Where, I ran into trouble, is when I realized nothing was checking if a job was valid. I want to check this in case a job name is spelled incorrectly, or if someone removes a job. I don't want to assume a job is being executed if it isn't. I added a check for valid SQL Agent Job name. This works, if the job names are valid. However, if the job name is not valid, the procedure gets stuck in a loop displaying the error message 'NO JOB' until I stop the procedure.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[usp_start_job_sequence8]
(
#JobList JobSequenceTable READONLY
,#PrntJob VARCHAR(100) = 'Unknown_Job'
)
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
SET QUOTED_IDENTIFIER ON;
SET ANSI_NULLS ON;
SET ANSI_PADDING ON;
SET ARITHABORT ON;
SET CONCAT_NULL_YIELDS_NULL ON;
SET NUMERIC_ROUNDABORT OFF;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SET ANSI_WARNINGS OFF;
---------------------************TRY BLOCK************---------------------
BEGIN TRY
BEGIN
DECLARE
#JobNumber TINYINT = 1
,#JobName VARCHAR(100)
,#IsRunning BIT
,#IsEnabled BIT
,#JOB_ID VARCHAR(60) = NULL
,#JOB_HIST_ID INT
,#JOB_STATUS VARCHAR(30)
,#JOB_STATUS_ID INT
,#esub VARCHAR(100)
,#ebdy VARCHAR(500)
,#Envt VARCHAR(4)
,#OVJOB_ID VARCHAR(60)
,#OVJOB_NAME VARCHAR(120)
,#JOB_TYPE CHAR(3)
,#epri VARCHAR(6);
--- Set server environment for emails
SELECT
#Envt = CASE WHEN ##SERVERNAME LIKE '%D%' THEN 'Dev'
WHEN ##SERVERNAME LIKE '%U%' THEN 'UAT'
WHEN ##SERVERNAME LIKE '%P%' THEN 'Prod'
WHEN ##SERVERNAME LIKE '%R%' THEN 'BCP'
ELSE ''
END
--- Set server environment for email priority
,#epri = CASE WHEN ##SERVERNAME LIKE '%D%' THEN 'Low'
WHEN ##SERVERNAME LIKE '%U%' THEN 'Normal'
WHEN ##SERVERNAME LIKE '%P%' THEN 'High'
WHEN ##SERVERNAME LIKE '%R%' THEN 'High'
ELSE ''
END;
BEGIN
WHILE (#JobNumber <= (SELECT
MAX(JobNumber)
FROM
#JobList
))
BEGIN
SELECT
#JobName = JobName
FROM
#JobList
WHERE
JobNumber = #JobNumber;
--VALID JOB?
IF NOT EXISTS(SELECT j.name FROM msdb.dbo.sysjobs_view J WITH(NOLOCK)
WHERE j.Name = #JobName)
BEGIN
PRINT 'NO JOB'
END;
ELSE
BEGIN
PRINT 'YES WE FOUND THE JOB';
--END
SELECT
#JOB_ID = job_id
FROM
msdb.dbo.sysjobs_view
WHERE
name = #JobName;
SELECT
#IsEnabled = enabled
FROM
msdb.dbo.sysjobs_view
WHERE
name = #JobName;
--- Very important step here. Ouvvi job names must start with Ouvvi
SELECT
#JOB_TYPE = CASE WHEN #JobName LIKE 'Ouvvi%'
THEN 'OVI'
ELSE 'SQL'
END;
--- Check if the job already running
SELECT
#IsRunning = dbo.fnJobStatusCheck(#JobName);
IF #IsRunning = 0
BEGIN
IF #IsEnabled = 0 --- Job is disabled error and send email
BEGIN
PRINT 'Job ' + #JobName
+ ' is disabled and cannot be started';
SET #esub = 'SQL Agent job '
+ #JobName + ' in ' + #Envt
+ ' is disabled and cannot be started';
SET #ebdy = 'SQL Agent job '
+ #JobName
+ ' was scheduled to run in box job '
+ #PrntJob + ' on server '
+ ##SERVERNAME + '. '
+ #JobName
+ ' could not start as it is disabled.'
+ CHAR(10) + CHAR(13)
+ +'The job ' + #JobName
+ ' should either be enabled, or removed from box job '
+ #PrntJob + '.';
EXEC msdb.dbo.sp_send_dbmail
--#profile_name = '',
-- #recipients = 'group#mail.com'
#recipients = 'person#mail.com',
#importance = #epri,
#subject = #esub,#body = #ebdy;
END;
ELSE ---- #IsEnabled = 1
----- Job is not running nor disabled. Split for different types
---OUVVI
BEGIN
IF #JOB_TYPE = 'OVI'
BEGIN
--PRINT 'OUVVI JOB'; --- TESTING
--- Parse Ouvvi Project ID - Used for success-failure
SET #OVJOB_ID = (SELECT
RTRIM(SUBSTRING(command,
CHARINDEX('/start/',
command) + 7,3))
FROM
msdb.dbo.sysjobsteps
WHERE
job_id = #JOB_ID
AND step_id = 1
);
--- START Ouvvi Job
EXEC msdb.dbo.sp_start_job #job_name = #JobName;
--PRINT #OVJOB_ID; --- TESTING
-- Waiting for the job to finish - Ouvvi jobs don't start immediately
WAITFOR DELAY '00:00:01';
WHILE (SELECT
1
FROM
Ouvvi.dbo.Queue
WHERE
ProjectID = #OVJOB_ID
) IS NOT NULL
BEGIN
WAITFOR DELAY '00:00:15';
IF (SELECT
1
FROM
Ouvvi.dbo.Queue
WHERE
ProjectID = #OVJOB_ID
) IS NULL
BREAK;
END;
--- Get Ouvvi Job Hist ID
SET #JOB_HIST_ID = (SELECT
Instance.ID
FROM
Ouvvi.dbo.Instance
WHERE
Instance.ProjectID = #OVJOB_ID
AND Instance.EndTime = (SELECT
MAX(EndTime)
FROM
Ouvvi.dbo.Instance
WHERE
Instance.ProjectID = #OVJOB_ID
)
);
--- Get Ouvvi Result
SET #JOB_STATUS_ID = (SELECT
ISNULL(I.Result,
9)
FROM
Ouvvi.dbo.Instance I
WHERE
I.ID = #JOB_HIST_ID
);
SET #JOB_STATUS = (SELECT
CASE
WHEN I.Result = 1
THEN 'Succeeded'
WHEN I.Result = 2
THEN 'Failed'
WHEN I.Result = 3
THEN 'Cancelled'
ELSE 'Unknown'
END
FROM
Ouvvi.dbo.Instance I
WHERE
I.ID = #JOB_HIST_ID
);
IF #JOB_STATUS_ID <> 1
BEGIN
PRINT #JobName
+ ' erred with the following status: '
+ #JOB_STATUS;
SET #esub = 'Ouvvi SQL Agent job '
+ #JobName
+ ' in ' + #Envt
+ ' erred with the following status: '
+ #JOB_STATUS;
SET #ebdy = 'An Ouvvi job, scheduled in SQL Agent '
+ #JobName
+ ' has erred with the following status: '
+ #JOB_STATUS
+ ' on server '
+ ##SERVERNAME
+ '.';
EXEC msdb.dbo.sp_send_dbmail
--#profile_name = '',
-- #recipients = 'group#mail.com'
#recipients = 'person#mail.com',
#importance = #epri,
#subject = #esub,
#body = #ebdy;
END;
END;
----Its a SQL Server Job
ELSE
BEGIN
EXEC msdb.dbo.sp_start_job #job_name = #JobName;
END;
WAITFOR DELAY '00:00:15.000';
SELECT
#IsRunning = dbo.fnJobStatusCheck(#JobName);
WHILE #IsRunning = 1
BEGIN
WAITFOR DELAY '00:00:15.000';
SELECT
#IsRunning = dbo.fnJobStatusCheck(#JobName);
END;
BEGIN
SET #JOB_HIST_ID = (SELECT
job_history_id
FROM
msdb.dbo.sysjobactivity
WHERE
job_id = #JOB_ID
AND run_requested_date = (SELECT
MAX(run_requested_date)
FROM
msdb.dbo.sysjobactivity
WHERE
job_id = #JOB_ID
)
);
SET #JOB_STATUS_ID = (SELECT
ISNULL(run_status,
9)
FROM
msdb.dbo.sysjobhistory
WHERE
instance_id = #JOB_HIST_ID
);
SET #JOB_STATUS = (SELECT
CASE
WHEN #JOB_STATUS_ID = 0
THEN 'Failed'
WHEN #JOB_STATUS_ID = 1
THEN 'Succeeded'
WHEN #JOB_STATUS_ID = 2
THEN 'Retry'
WHEN #JOB_STATUS_ID = 3
THEN 'Cancelled'
ELSE 'Unknown'
END
);
BEGIN
IF #JOB_STATUS_ID <> 1
BEGIN
PRINT #JobName
+ ' erred with the following status: '
+ #JOB_STATUS;
SET #esub = 'SQL Agent job '
+ #JobName
+ ' in ' + #Envt
+ ' erred with the following status: '
+ #JOB_STATUS;
SET #ebdy = 'SQL Agent job '
+ #JobName
+ ' erred with the following status: '
+ #JOB_STATUS
+ ' on server '
+ ##SERVERNAME
+ '.';
EXEC msdb.dbo.sp_send_dbmail
--#profile_name = '',
-- #recipients = 'group#mail.com'
#recipients = 'person#mail.com',
#importance = #epri,
#subject = #esub,
#body = #ebdy;
END;
END;
END;
END;
SET #JOB_ID = NULL;
SET #JobNumber = #JobNumber + 1;
END;
END;
END;
END;
END;
END TRY
---------------------*********************************--------------------
---------------------************CATCH BLOCK**********-------------------
BEGIN CATCH
-- Print Error Information
DECLARE #ERRORMESSAGE NVARCHAR(4000);
DECLARE #ERRORSEVERITY INT;
DECLARE #ERRORSTATE INT;
SELECT
#ERRORMESSAGE = ERROR_MESSAGE()
,#ERRORSEVERITY = ERROR_SEVERITY()
,#ERRORSTATE = ERROR_STATE();
RAISERROR (#ERRORMESSAGE, #ERRORSEVERITY, #ERRORSTATE);
-- Rollback uncommittable transactions
IF (XACT_STATE()) = -1
BEGIN
PRINT 'The transaction is in an uncommittable state.'
+ ' Rolling back transaction.';
ROLLBACK TRANSACTION;
END;
-- Inserting error related information into the Error Log table
INSERT INTO dbo.tbl_Object_ErrorLog
(ObjectName
,ErrorNumber
,ErrorMessage
,ErrorSeverity
,ErrorState
,ErrorlINE
,SystemUser
,LogDate
)
SELECT
ERROR_PROCEDURE()
,ERROR_NUMBER()
,ERROR_MESSAGE()
,ERROR_SEVERITY()
,ERROR_STATE()
,ERROR_LINE()
,SYSTEM_USER
,GETDATE();
END CATCH;
---------------------********************************----------------------
END;
GO
Code to launch the procedure:
SET ANSI_WARNINGS OFF
GO
DECLARE #JobList AS JobSequenceTable
INSERT INTO #JobList
VALUES
('x_test3')
,('NoJobHere')
,('x_test1')
EXEC dba.dbo.usp_start_job_sequence8 #JobList, 'TESTING'
What I want to happen is: when it checks for valid job name, prints NO JOB and ends, it should go to line 378, add 1 to #JobNumber, end that round, going to the next job.
I can't figure out why it's stuck in the loop.
Thanks for any help.
As your loop is very long with nested blocks and hard to debug, I would do the following:
- before jumping in the loop, validate which jobs are missing
- create a table that holds the missing jobs, e.g. #MissingJobs, and do your stuff with them before you do with the existing jobs
- based on #MissingJobs remove the missing jobs from the #JobList table and then loop through those, so in this case no need to debug the long loop block. Or create a new table if you need the original and use that in the loop - but in that case more work to change everywhere from #JobList to the new one. You can get back the original list if you UNION ALL the reduced #JobList with #MissingJobs. Anyway you do, you need to remove the block after --VALID JOB? (till PRINT 'YES WE FOUND THE JOB';) as you can PRINT those out based on this logic - in this case you must also remove an END after SET #JobNumber = #JobNumber + 1; because you remove an unclosed ELSE BEGIN.
Related
I currently have a SQL script that takes all the tables with a certain name and deletes records from it.
There are millions of records in these tables so the transaction log keeps growing even with recovery set to SIMPLE. I am putting the delete in side a transaction and it's only deleting around 50000 records at a time. Can anyone suggest some way to not let the transaction log grow uncontrollably. Below is the rough example of the SQL I am running.
DECLARE delete_cur CURSOR FOR
SELECT DISTINCT Name FROM Sys.tables WHERE name like 'ToDelete_%'
OPEN delete_cur
FETCH NEXT FROM delete_cur
INTO #tableName
WHILE ##FETCH_STATUS = 0 AND #timeToStop = 0
BEGIN
SELECT #RowCount = NULL, #MaxID = NULL, #MinID = NULL, #ID = NULL, #TableRowCount = 0
IF NOT Exists (Select 1 from ArchiveInfoAuditTables WHERE Name = #tableName)
BEGIN
SET #params = N'#MaxID_Out DECIMAL(18,0) OUT, #MinID_Out DECIMAL(18,0) OUT, #RowCount_Out DECIMAL(18,0) OUT';
SET #SQL = 'SELECT #RowCount_Out = COUNT(ID), #MaxID_Out = MAX(ID), #MinID_Out = MIN(ID) FROM ' + #tableName
print #SQL
EXEC sp_executesql #SQL, #params, #RowCount_Out = #RowCount OUT, #MaxID_Out = #MaxID OUT, #MinID_Out = #MinID OUT;
PRINT #tableName + ' Row Count: ' + CONVERT(VARCHAR, #RowCount) + ' Max ID: ' + CONVERT(VARCHAR, #MaxID) + ' Min ID: ' + CONVERT(VARCHAR, #MinID)
SET #params = N'#ID_Out DECIMAL(18,0) OUT, #Date DATETIME';
SET #SQL = 'SELECT TOP 1 #ID_Out = ID FROM ' + #tableName + ' WHERE AuditTimeStamp < #Date ORDER BY ID DESC'
print #SQL
EXEC sp_executesql #SQL, #params, #ID_Out = #ID OUT, #Date = #JanOfCurrentYear
INSERT INTO DeleteInfo (Name, StartDeletingFromID, MaxID, MinID, NumberOfRows)
VALUES (#tableName, #ID, #MaxID, #MinID, #RowCount)
END
ELSE
BEGIN
SELECT TOP 1 #ID = StartDeletingFromID FROM DeleteInfo WHERE Name = #tableName
END
IF (#ID IS NULL)
BEGIN
PRINT 'No Record needs to be deleted for Table: ' + #tableName
GOTO Fetch_Next
END
WHILE 1 = 1
BEGIN
BEGIN TRANSACTION
SET #params = N'#RowCount_Out DECIMAL(18,0) OUT, #NumOfRowsToDelete_Out BIGINT, #ID_Out DECIMAL(18,0)'
SET #SQL = 'DELETE TOP (#NumOfRowsToDelete_Out) FROM ' + #tableName + ' WHERE ID <= #ID_Out ;'
+ 'SELECT #RowCount_Out = ##RowCount'
PRINT #SQL
EXEC sp_executesql #SQL, #params, #RowCount_Out = #TempRowCount OUT, #NumOfRowsToDelete_Out = #NumOfRowsToDelete, #ID_Out = #ID
SET #TableRowCount += #TempRowCount
SET #TotalRowCount += #TableRowCount
COMMIT TRANSACTION
CHECKPOINT;
SET #MSG = 'Deleted ' + CAST(#TableRowCount AS VARCHAR) + '. ' + CONVERT(varchar, #TimeElapsed) + ' elapsed.'
RAISERROR (#MSG, 0, 1) WITH NOWAIT
IF #TempRowCount < #NumOfRowsToDelete BREAK;
END
Fetch_Next:
PRINT '/******************************************************************/'
FETCH NEXT FROM delete_cur
INTO #tableName
END
END_HERE:
CLOSE delete_cur;
DEALLOCATE delete_cur;
You can limit the size of the log (here we limit the size to 512 MB):
ALTER DATABASE [DatabaseName] MODIFY FILE ( NAME = N'DATABASENAME_Log', SIZE = 512000KB , FILEGROWTH = 0)
Create a maintenance job for backups the DB and shrinks the log
you can use this simple command to shrink the log file
DBCC SHRINKFILE (DataFile1, 512)
I have a procedure that generates dynamic SQL that creates an insert into statement while querying an excel spreadsheet.
The resulting print from the messages screen can be pasted into an ssms window and executes. When I try to execute the SQL from within the stored procedure I get a syntax error as follows:
'SELECT * into TestClient FROM OPENROWSET('Microsoft.ACE.OLEDB.12.0', 'Excel 12.0;HDR=YES;Database=G:\CustomerETL\Employee\PendingETL\ETLEmployeexls.xls;', [Sheet1$])'
Msg 102, Level 15, State 1, Line 15
Incorrect syntax near 'SELECT * into TestClient FROM OPENROWSET('.
Below is the entire stored procedure. I know the problem is in the ticks (within the SET blocks that create the dynamic SQL I just can't figure out where the missing ticks are.
Here is the proc:
USE [ETL]
GO
/****** Object: StoredProcedure [dbo].[ImportExcelSheetForCustomerEmployeeUpdate2] Script Date: 12/19/2017 4:03:05 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[ImportExcelSheetForCustomerEmployeeUpdate2](#BatchID int)
as
--EXEC ImportExcelSheetForCustomerEmployeeUpdate 2
/* -- TRUNCATE TABLE FilesToImport
UPDATE FilesToImport
SET StatusID = 1
*/
-- Jeffery Williams
-- 12/18/2017
DECLARE #FileID int
,#ETLFilename varchar(250)
,#ClientName varchar(100)
,#FileType varchar(5)
,#ColumnCount int
,#RowsToETL int
,#StatusID int
,#Processed bit = 0
,#Count int
,#SQL nvarchar(4000)
,#Sheetname varchar(50) = '[Sheet1$]'
,#CMDSQL as varchar(4000)
,#SQLCmd NVARCHAR(MAX)
SELECT *
FROM FilesToImport
BEGIN
SELECT #Count = count(*)
FROM FilesToImport
WHERE BatchID = #BatchID
AND StatusID = 1
END
PRINT 'Count of records to process: ' + cast(#Count as varchar)
WHILE #Count > 0
BEGIN
BEGIN
SELECT TOP 1 #FileID = FileID, #ETLFilename = ETLFilename, #ClientName = ClientName
,#FileType = FileType, #ColumnCount = ColumnCount, #RowsToETL = RowsToETL
FROM FilesToImport
WHERE StatusID = 1
AND BatchID = #BatchID
END
-- Rename the file
set #CMDSQL = 'rename G:\CustomerETL\Employee\PendingETL\' + #ETLFilename + ' ETLEmployeexls.xls'
exec master..xp_cmdshell #CMDSQL
--PRINT cast(#cmdsql as varchar(4000))
-- Ciode below generates our select. Need to add an INTO clause and create a staging table for each import. Prior to this step we need to rename the file.
SET #SQL = ''''
SET #SQL = #SQL + 'SELECT * into ' + coalesce(#ClientName, 'TestClient') + ' FROM OPENROWSET('
SET #SQL = #SQL + ''''
SET #SQL = #SQL + '''' + 'Microsoft.ACE.OLEDB.12.0' + '''' --+ ', '
-- Excel 12.0;HDR=NO;Database=g:\UnZip\ImportSampleXLSX.xlsx;' + ''
SET #SQL = #SQL + '''' + ', '
SET #SQL = #SQL + '''' + '''Excel 12.0;HDR=YES;Database=G:\CustomerETL\Employee\PendingETL\ETLEmployeexls.xls;''' + '''' + ', ' + #Sheetname + ')'
SET #SQL = #SQL + ''''
PRINT cast(#SQL as varchar(8000))
EXEC sp_executesql #SQL
set #CMDSQL = 'rename G:\CustomerETL\Employee\PendingETL\ETLEmployeexls.xls ' + #ETLFilename
exec master..xp_cmdshell #CMDSQL
UPDATE FilesToImport
SET StatusID = 2
WHERE FileID = #FileID
/* -- TRUNCATE TABLE FilesToImport
UPDATE FilesToImport
SET StatusID = 1
*/
SET #Count = (#Count - 1)
CONTINUE
END
I am posting this as an answer but it should be comment. When I tried adding this as a comment StackOveflow kept thinking that I was trying to add #count as an email target.
In your code:
WHILE #Count > 0
BEGIN
BEGIN
SELECT TOP 1 #FileID = FileID, #ETLFilename = ETLFilename, #ClientName = ClientName
,#FileType = FileType, #ColumnCount = ColumnCount, #RowsToETL = RowsToETL
FROM FilesToImport
WHERE StatusID = 1
AND BatchID = #BatchID
END
you are not updating the value of #count. This will either never loop or loop forever. You probably want to add a statement (right before the end) such as this:
Set #count= ##rowcount;
Ben
I'm trying to follow the link in order to send automated emails with the descriptions of the job failures.
However, when I'm trying to pass these arguments into the procedure:
EXEC msdb.dbo.TestMail
#job_id = '$(ESCAPE_SQUOTE(JOBID))'
,#strtdt = '$(ESCAPE_SQUOTE(STRTDT))'
,#strttm = '$(ESCAPE_SQUOTE(STRTTM))'
,#operator_name = 'MSXOperator'
,#mail_on_success = 'Y'
,#attach_output_file = 'ON_FAILUR
I see the following error:
Msg 8114, Level 16, State 5, Procedure TestMail, Line 0
Error converting data type varchar to uniqueidentifier.
The code for TestMail is
USE msdb
GO
IF OBJECT_ID('dbo.TestMail') IS NOT NULL DROP PROC dbo.TestMail
GO
CREATE PROC dbo.TestMail
#job_id uniqueidentifier
,#strtdt varchar(100)
,#strttm varchar(100)
,#operator_name sysname = 'MSXOperator'
,#mail_on_success char(1) = 'Y' --'Y', 'N'
,#attach_output_file varchar(10) = 'ON_FAILURE' --'ALWAYS', 'NEVER', 'ON_FAILURE'
AS
SET NOCOUNT ON
DECLARE
#job_name sysname
,#job_id_str varchar(200) --GUID representation as string without hyphens
,#email_address nvarchar(300)
,#run_status int --0 = Failed, 1 = Succeeded, 2 = Retry, 3 = Canceled
,#run_status_desc varchar(9) --Failed, Succeeded, Retry, Canceled
,#importance varchar(6) --low, normal, high
,#output_file_names varchar(max)
,#subject nvarchar(255)
,#body nvarchar(max)
,#step_name sysname --to hold name of jobstep
,#step_duration int
,#step_duration_str varchar(20)
,#job_duration int
,#job_duration_str varchar(20)
,#step_id int
,#step_run_status int
,#step_run_status_desc varchar(9)
,#crlf char(2)
,#send_mail_bit bit --calculated just before send mail routine
,#attach_output_file_bit bit --calculated just before send mail routine
,#ag_tkn_step_id varbinary(200)
,#ag_tkn_job_id varbinary(200)
,#ag_tkn_strt_dt varbinary(200)
,#ag_tkn_strt_tm varbinary(200)
,#ag_tkn_mach_nm varbinary(200)
,#ag_tkn_inst_nm varbinary(200)
SET #crlf = CHAR(13) + CHAR(10)
SET #body = ''
------------------------------------------------------------------------------------------------------------------------------
--We can't represent agent tokens as strings if we want to push this proc out from an MSX server.
--The first SELECT is only used in dev, to ger each strin representation as varbinary.
-- This will look weird when deployed on a TSX server.
--The second part sets each variable to a varbinary representation of each string.
--The variable are used later in the proc
------------------------------------------------------------------------------------------------------------------------------
--SELECT
-- CAST('$(ESCAPE_SQUOTE(STEPID))' AS varbinary(200))
--,CAST('$(ESCAPE_SQUOTE(JOBID))' AS varbinary(200))
--,CAST('$(ESCAPE_SQUOTE(STRTDT))' AS varbinary(200))
--,CAST('$(ESCAPE_SQUOTE(STRTTM))' AS varbinary(200))
--,CAST('$(ESCAPE_SQUOTE(MACH))' AS varbinary(200))
--,CAST('$(ESCAPE_SQUOTE(INST))' AS varbinary(200))
SET #ag_tkn_step_id = 0x24284553434150455F5351554F5445285354455049442929
SET #ag_tkn_job_id = 0x24284553434150455F5351554F5445284A4F4249442929
SET #ag_tkn_strt_dt = 0x24284553434150455F5351554F5445285354525444542929
SET #ag_tkn_strt_tm = 0x24284553434150455F5351554F54452853545254544D2929
SET #ag_tkn_mach_nm = 0x24284553434150455F5351554F5445284D4143482929
SET #ag_tkn_inst_nm = 0x24284553434150455F5351554F544528494E53542929
------------------------------------------------------------------------------------------------------------------------------
--Validate input parameters
-------------------------------------------------------------------------------------------------------------------------------
IF #mail_on_success NOT IN('Y', 'N')
BEGIN
RAISERROR('Bad value for parameter #mail_on_success, values allowed are ''Y'' and ''N''.', 16, 1)
RETURN
END
IF #attach_output_file NOT IN ('ALWAYS', 'NEVER', 'ON_FAILURE')
BEGIN
RAISERROR('Bad value for parameter #attach_output_file, values allowed are ''ALWAYS'', ''NEVER'' andd ''ON_FAILURE''.', 16, 1)
RETURN
END
-------------------------------------------------------------------------------------------------------------------------------
--Get job name
------------------------------------------------------------------------------------------------------------------------------
SET #job_name = (SELECT s.name FROM msdb.dbo.sysjobs AS s WHERE s.job_id = #job_id)
IF #job_name IS NULL
BEGIN
RAISERROR('Failed to retreive job name baed on #job_id, teminating procedure MailAfterJob.', 16, 1)
RETURN
END
------------------------------------------------------------------------------------------------------------------------------
--String representation of job_id (to match representation in file name)
------------------------------------------------------------------------------------------------------------------------------
SET #job_id_str = UPPER(master.dbo.fn_varbintohexstr(#job_id))
------------------------------------------------------------------------------------------------------------------------------
--Get email_address for operator
-------------------------------------------------------------------------------------------------------------------------------
SET #email_address = (SELECT o.email_address FROM msdb.dbo.sysoperators AS o WHERE o.name = #operator_name)
IF #email_address IS NULL
BEGIN
RAISERROR('Unknown mail operator name, teminating procedure MailAfterJob.', 16, 1)
RETURN
END
------------------------------------------------------------------------------------------------------------------------------
--Get job outcome for *this* execuution, store in table variable
------------------------------------------------------------------------------------------------------------------------------
DECLARE #jobhistory table(instance_id int, step_id int, run_status int, step_name sysname, step_duration int)
INSERT INTO #jobhistory (instance_id, step_id, run_status, step_name, step_duration)
SELECT instance_id, step_id, run_status, step_name, run_duration
FROM msdb.dbo.sysjobhistory AS h
WHERE h.job_id = #job_id
AND msdb.dbo.agent_datetime(h.run_date, h.run_time) >= msdb.dbo.agent_datetime(CAST(#strtdt AS int), CAST(#strttm AS int))
------------------------------------------------------------------------------------------------------------------------------
--Get lowest run status for this execution (0 = fail)
------------------------------------------------------------------------------------------------------------------------------
SET #run_status = (SELECT MIN(h.run_status)
FROM #jobhistory AS h
INNER JOIN msdb.dbo.sysjobhistory AS hi ON hi.instance_id = h.instance_id
WHERE hi.job_id = #job_id)
IF #run_status IS NULL
BEGIN
RAISERROR('Could not determine run status for job, teminating procedure MailAfterJob.', 16, 1)
RETURN
END
SET #run_status_desc = CASE #run_status
WHEN 0 THEN 'FAILED'
WHEN 1 THEN 'SUCCEEDED'
WHEN 2 THEN 'RETRY'
WHEN 3 THEN 'CANCELED'
END
------------------------------------------------------------------------------------------------------------------------------
--Set importance for email
------------------------------------------------------------------------------------------------------------------------------
IF #run_status = 0
SET #importance = 'high'
ELSE
SET #importance = 'low'
------------------------------------------------------------------------------------------------------------------------------
--Get output file names to attach to email, in table variable
------------------------------------------------------------------------------------------------------------------------------
DECLARE #output_file_names_table table(output_file_name_step varchar(300))
INSERT INTO #output_file_names_table(output_file_name_step)
SELECT REPLACE(COALESCE(s.output_file_name, ''), CAST(#ag_tkn_step_id AS varchar(200)), CAST(s.step_id AS varchar(20))) AS out_file_name
FROM msdb.dbo.sysjobsteps AS s
WHERE s.job_id = #job_id
AND s.output_file_name IS NOT NULL
AND EXISTS(SELECT * FROM #jobhistory AS h WHERE h.step_id = s.step_id)
--Replace agent tokens with actual values
UPDATE #output_file_names_table SET output_file_name_step = REPLACE(output_file_name_step, CAST(#ag_tkn_job_id AS varchar(200)), #job_id_str)
UPDATE #output_file_names_table SET output_file_name_step = REPLACE(output_file_name_step, CAST(#ag_tkn_strt_dt AS varchar(200)), #strtdt)
UPDATE #output_file_names_table SET output_file_name_step = REPLACE(output_file_name_step, CAST(#ag_tkn_strt_tm AS varchar(200)), #strttm)
UPDATE #output_file_names_table SET output_file_name_step = REPLACE(output_file_name_step, CAST(#ag_tkn_mach_nm AS varchar(200)), CAST(SERVERPROPERTY('MachineName') AS varchar(100)))
UPDATE #output_file_names_table SET output_file_name_step = REPLACE(output_file_name_step, CAST(#ag_tkn_inst_nm AS varchar(200)), (ISNULL(CAST(SERVERPROPERTY('InstanceName') AS varchar(100)), '')))
--Loop table with file names, create semi-colon separated string
DECLARE #output_file_name_step varchar(300)
SET #output_file_names = ''
DECLARE c CURSOR FOR SELECT DISTINCT output_file_name_step FROM #output_file_names_table
OPEN c
WHILE 1 = 1
BEGIN
FETCH NEXT FROM c INTO #output_file_name_step
IF ##FETCH_STATUS <> 0
BREAK
SET #output_file_names = #output_file_names + #output_file_name_step + ';'
END
CLOSE c
DEALLOCATE c
--Remove the last semi-colon
IF LEN(#output_file_names) > 0
SET #output_file_names = SUBSTRING(#output_file_names, 1, LEN(#output_file_names) - 1)
------------------------------------------------------------------------------------------------------------------------------
--Construct email parts
------------------------------------------------------------------------------------------------------------------------------
--Set mail subject
--SET #subject = ##SERVERNAME + ' ' + #run_status_desc + ' ' + #job_name
SET #subject = CASE WHEN #run_status_desc = 'SUCCEEDED' THEN 'Ok' ELSE #run_status_desc END + ': ' + #job_name
--Set mail body
DECLARE c cursor FOR SELECT h.step_id, h.step_name, h.step_duration, h.run_status FROM #jobhistory AS h ORDER BY instance_id
OPEN c
WHILE 1 = 1
BEGIN
FETCH NEXT FROM c INTO #step_id, #step_name, #step_duration, #step_run_status
IF ##FETCH_STATUS <> 0
BREAK
SET #step_duration_str = RIGHT('00000' + CAST(#step_duration AS varchar(6)), 6) --Make sure we have 0:s first
SET #step_duration_str = SUBSTRING(#step_duration_str, 1, 2) + ':' +
SUBSTRING(#step_duration_str, 3, 2) + ':' + SUBSTRING(#step_duration_str, 5, 2)
SET #step_run_status_desc = CASE #step_run_status
WHEN 0 THEN 'FAILED'
WHEN 1 THEN 'SUCCEEDED'
WHEN 2 THEN 'RETRY'
WHEN 3 THEN 'CANCELED'
END
IF #step_id <> 0
SET #body = #body + 'Step "' + #step_name + '" executed ' + #step_run_status_desc + ', time ' + #step_duration_str + '.' + #crlf
END
CLOSE c
DEALLOCATE c
SET #job_duration = (SELECT SUM(step_duration) FROM #jobhistory)
SET #job_duration_str = RIGHT('00000' + CAST(#job_duration AS varchar(6)), 6) --Make sure we have 0:s first
SET #job_duration_str = SUBSTRING(#job_duration_str, 1, 2) + ':' +
SUBSTRING(#job_duration_str, 3, 2) + ':' + SUBSTRING(#job_duration_str, 5, 2)
SET #body = 'Job executed, time ' + #job_duration_str + '.' + #crlf + #crlf + #body
------------------------------------------------------------------------------------------------------------------------------
--Decide whether to send email
------------------------------------------------------------------------------------------------------------------------------
IF (#mail_on_success = 'N' AND #run_status = 1) --1 = Success
SET #send_mail_bit = 0
ELSE
SET #send_mail_bit = 1
------------------------------------------------------------------------------------------------------------------------------
--Decide whether to attach output file
------------------------------------------------------------------------------------------------------------------------------
SET #attach_output_file_bit = 0
IF #attach_output_file = 'ALWAYS'
SET #attach_output_file_bit = 1
IF #attach_output_file = 'NEVER'
SET #attach_output_file_bit = 0
IF #attach_output_file = 'ON_FAILURE' AND #run_status <> 1 --1 = Success
SET #attach_output_file_bit = 1
------------------------------------------------------------------------------------------------------------------------------
--Send the email
------------------------------------------------------------------------------------------------------------------------------
IF #send_mail_bit = 1
BEGIN
IF #attach_output_file_bit = 0
EXEC msdb.dbo.sp_send_dbmail --Do no attach output file
#recipients = #email_address
,#subject = #subject
,#body = #body
,#importance = #importance
ELSE
EXEC msdb.dbo.sp_send_dbmail --Do attach output file
#recipients = #email_address
,#subject = #subject
,#body = #body
,#importance = #importance
,#file_attachments = #output_file_names
END
------------------------------------------------------------------------------------------------------------------------------
--Exit with fail if we got here on failure
------------------------------------------------------------------------------------------------------------------------------
IF #run_status = 0
RAISERROR('Job failed', 16, 1)
------------------------------------------------------------------------------------------------------------------------------
/*
--Sample execution, as to be defined in job (this can look weird when deployed on TSX server)
EXEC sqlmaint.dbo.MailAfterJob
#job_id = $(ESCAPE_SQUOTE(JOBID))
,#strtdt = '$(ESCAPE_SQUOTE(STRTDT))'
,#strttm = '$(ESCAPE_SQUOTE(STRTTM))'
,#operator_name = 'MSXOperator'
,#mail_on_success = 'Y'
,#attach_output_file = 'ON_FAILURE' --'ALWAYS', 'NEVER', 'ON_FAILURE'
*/
------------------------------------------------------------------------------------------------------------------------------
GO
The link is: http://www.karaszi.com/sqlserver/util_MailAfterJob.asp
I was able to duplicate the error; it indicates the problem exactly. The problem is that you are quoting the token '$(ESCAPE_SQUOTE(JOBID))' causing the proc to think you are passing a string, implicitly converted to VARCHAR. Since VARCHAR doesn't implicitly convert to the defined UNIQUEIDENTIFIER, you get your error.
If you simply remove the quotes, in the job step, everything works as designed. Hopefully, you aren't trying to test this outside of a SQL Agent job or it will fail no matter what you do.
Simplified Proc to Address the conversion error:
use msdb
go
if OBJECT_ID('testString','P') is null
execute sp_executesql N'CREATE PROC testString as select ''stub'' stubProc'
go
alter proc testString
#job_id uniqueidentifier
as
declare #job_id_str varchar(200)
SET #job_id_str = UPPER( master.dbo.fn_varbintohexstr( #job_id ) )
select #job_id jobID, #job_id_str jobIDStr
Test job
USE [msdb]
GO
/****** Object: Job [id TEST] Script Date: 6/8/2016 9:06:06 AM ******/
EXEC msdb.dbo.sp_delete_job #job_name=N'id TEST', #delete_unused_schedule=1
GO
/****** Object: Job [id TEST] Script Date: 6/8/2016 9:06:06 AM ******/
BEGIN TRANSACTION
DECLARE #ReturnCode INT
SELECT #ReturnCode = 0
/****** Object: JobCategory [[Uncategorized (Local)]] Script Date: 6/8/2016 9:06:06 AM ******/
IF NOT EXISTS (SELECT name FROM msdb.dbo.syscategories WHERE name=N'[Uncategorized (Local)]' AND category_class=1)
BEGIN
EXEC #ReturnCode = msdb.dbo.sp_add_category #class=N'JOB', #type=N'LOCAL', #name=N'[Uncategorized (Local)]'
IF (##ERROR <> 0 OR #ReturnCode <> 0) GOTO QuitWithRollback
END
DECLARE #jobId BINARY(16)
EXEC #ReturnCode = msdb.dbo.sp_add_job #job_name=N'id TEST',
#enabled=1,
#notify_level_eventlog=0,
#notify_level_email=0,
#notify_level_netsend=0,
#notify_level_page=0,
#delete_level=0,
#description=N'No description available.',
#category_name=N'[Uncategorized (Local)]',
#owner_login_name=N'DOMAIN\USER', #job_id = #jobId OUTPUT
IF (##ERROR <> 0 OR #ReturnCode <> 0) GOTO QuitWithRollback
/****** Object: Step [TEST] Script Date: 6/8/2016 9:06:06 AM ******/
EXEC #ReturnCode = msdb.dbo.sp_add_jobstep #job_id=#jobId, #step_name=N'TEST',
#step_id=1,
#cmdexec_success_code=0,
#on_success_action=1,
#on_success_step_id=0,
#on_fail_action=2,
#on_fail_step_id=0,
#retry_attempts=0,
#retry_interval=0,
#os_run_priority=0, #subsystem=N'TSQL',
#command=N'EXEC msdb.dbo.testString
#job_id = $(ESCAPE_SQUOTE(JOBID))',
#database_name=N'master',
#flags=0
IF (##ERROR <> 0 OR #ReturnCode <> 0) GOTO QuitWithRollback
EXEC #ReturnCode = msdb.dbo.sp_update_job #job_id = #jobId, #start_step_id = 1
IF (##ERROR <> 0 OR #ReturnCode <> 0) GOTO QuitWithRollback
EXEC #ReturnCode = msdb.dbo.sp_add_jobserver #job_id = #jobId, #server_name = N'(local)'
IF (##ERROR <> 0 OR #ReturnCode <> 0) GOTO QuitWithRollback
COMMIT TRANSACTION
GOTO EndSave
QuitWithRollback:
IF (##TRANCOUNT > 0) ROLLBACK TRANSACTION
EndSave:
GO
There are stored procedures written to copy data from one database and insert into different database. but currently the procedures taking so much time for the process to complete. Why is this happening and how to reduce the running time for procedures?
My code:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [PPA].[SP_LOAD_PR_FROM_PEOPLESOFT]
#success BIT OUTPUT
AS
--//Declaring the variables
DECLARE #MessageDescription VARCHAR(200)
DECLARE #Message VARCHAR(1000)
DECLARE #REQ_ID VARCHAR(10)
DECLARE #BUSINESS_UNIT CHAR(5)
DECLARE #CURRENCY_CD CHAR(3)
DECLARE #CNT_REQUESTS NUMERIC
DECLARE #REVISION_NUMBER NUMERIC(18,0)
DECLARE #PS_DATE_MODIFIED DATETIME
DECLARE #PPA_DATE_MODIFIED DATETIME
DECLARE #REQUEST_STATUS_CODE NUMERIC(18,0)
DECLARE #REQUEST_ID NUMERIC(38,0)
DECLARE #PS_DATE_CREATED DATETIME
BEGIN
SET #success = 0
SET #MessageDescription = 'Stored procedure SP_LOAD_PR_FROM_PEOPLESOFT '
PRINT 'Inside ' + #MessageDescription
--//DECLARE the CURSOR to retrieve approved PRs from PeopleSoft's table PS_REQ_HDR
DECLARE cursor_ps_req_hdr CURSOR READ_ONLY FOR
SELECT
BUSINESS_UNIT,
LTRIM(RTRIM(REQ_ID)) AS REQ_ID,
CURRENCY_CD,
LAST_DTTM_UPDATE, ---- get PR UPDATION date time :to address issue C_42
REQ_DT ---- get PR CREATION date time :to address issue C_42
FROM PPA_PS_DAILY.PPA.PS_REQ_HDR
WHERE REQ_STATUS IN ('P', 'A')
AND HOLD_STATUS = 'N'
AND BUSINESS_UNIT IN ('GLPO1', 'ILPO1', 'INPO1', 'SOPO1', 'SSPO1' ,'TSPO1','USPO1','AUPO1','CNPO1','FRPO1','SCPO1','UKPO2','SIPO1')
ORDER BY BUSINESS_UNIT, REQ_ID
OPEN cursor_ps_req_hdr
------------------------------------------
PRINT 'Count of rows before fetching in cursor cursor_ps_req_hdr : '+cast(##cursor_rows as varchar)
------------------------------------------
FETCH NEXT FROM cursor_ps_req_hdr INTO
#BUSINESS_UNIT,
#REQ_ID,
#CURRENCY_CD,
#PS_DATE_MODIFIED, -- to address issue C_42
#PS_DATE_CREATED -- to address issue C_42
--//Check ##FETCH_STATUS to see if there are any records to retrieve.
IF ##FETCH_STATUS <> 0
BEGIN
--//No approved PRs exist in table PS_REQ_HDR
SET #Message = #MessageDescription + ': No approved PRs to retrieve from table PS_REQ_HDR.'
PRINT #Message
--//log message in a log file
END
WHILE ##FETCH_STATUS = 0
BEGIN
--Check if retrieved PR has associated request in PPA
SELECT #CNT_REQUESTS = COUNT(*)
FROM PPA.REQUEST REQ
WHERE REQ.PR_NUMBER = #REQ_ID
AND REQ.BUYER_COMPANY_ID = #BUSINESS_UNIT
IF #CNT_REQUESTS = 0 --If no associated request exists for a PR
BEGIN
SET #REVISION_NUMBER = 0 -- to address issue C_42
--insert new request and its line items into PPA back end
EXEC PPA.SP_INSERT_REQUEST #REQ_ID, #BUSINESS_UNIT, #CURRENCY_CD,#REVISION_NUMBER,#PS_DATE_CREATED,#PS_DATE_MODIFIED,#success --Added #REVISION_NUMBER,#PS_DATE_CREATED,#PS_DATE_MODIFIED :to address issue C_42
IF #success = 0
BEGIN
SET #Message = #MessageDescription + ': Failed to INSERT request and/or its line items into PPA back-end for REQ_ID = ' + #REQ_ID + ' BUSINESS_UNIT = ' + #BUSINESS_UNIT
END
END
ELSE --If associated request exists for a PR in PPA
BEGIN
-----------------------------------------------addressing issue C_42: Start---------------------------------------------------------------------
--Check request status and find
PS_DATE_MODIFIED,REQUEST_ID,REVISION_NUMBER for the request at PPA end
SELECT TOP 1 #REQUEST_ID=REQ.REQUEST_ID,#REQUEST_STATUS_CODE=REQ.REQUEST_STATUS_CODE,
#REVISION_NUMBER = REQ.REVISION_NUMBER,#PPA_DATE_MODIFIED = REQ.PS_DATE_MODIFIED
FROM PPA.REQUEST REQ
WHERE REQ.PR_NUMBER = #REQ_ID
AND REQ.BUYER_COMPANY_ID = #BUSINESS_UNIT
ORDER BY REQ.REVISION_NUMBER DESC,REQ.DATE_CREATED DESC
--Check if there is any difference in modified dates at PS and PPA end
IF #PS_DATE_MODIFIED!=#PPA_DATE_MODIFIED
BEGIN
SET #Message = #MessageDescription + ' : Request status code for REQUEST_ID '+CAST(#REQUEST_ID AS VARCHAR)+' REQ_ID = ' + #REQ_ID + ' BUSINESS_UNIT = ' + #BUSINESS_UNIT+' is '+CAST(#REQUEST_STATUS_CODE AS VARCHAR)
PRINT #Message
--Check if request at PPA end has request status code other than 10(incomplete)
IF #REQUEST_STATUS_CODE <> 10
BEGIN
SET #REVISION_NUMBER = #REVISION_NUMBER+1
--insert new request and its line items into PPA back end with next revision number
EXEC PPA.SP_INSERT_REQUEST #REQ_ID, #BUSINESS_UNIT, #CURRENCY_CD,#REVISION_NUMBER,#PS_DATE_CREATED,#PS_DATE_MODIFIED,#success --Added #REVISION_NUMBER,#PS_DATE_CREATED,#PS_DATE_MODIFIED :to address issue C_42
IF #success = 0
BEGIN
SET #Message = #MessageDescription + ': Failed to INSERT request and/or its line items into PPA back-end for REQ_ID = ' + #REQ_ID + ' BUSINESS_UNIT = ' + #BUSINESS_UNIT
PRINT #Message
END
END
ELSE -- Process the PR if request_status is incomplete i.e.(request_status_code=10)
BEGIN
--Update the PR into PPA back end
EXEC PPA.SP_UPDATE_ITEMS_OF_PR #REQ_ID, #BUSINESS_UNIT, #CURRENCY_CD,#REVISION_NUMBER,#REQUEST_ID,#PS_DATE_MODIFIED,#PS_DATE_CREATED, #success
IF #success = 0
BEGIN
SET #Message = #MessageDescription + ': Failed to UPDATE request into PPA back-end for PR_NUMBER = ' + #REQ_ID + ' BUSINESS_UNIT = ' + #BUSINESS_UNIT
PRINT #Message
END
END
END
-- Updated by Kunal, Calling to update PR items regardless of the state of the request
if(select count(*) from PPA.REQ_LINE_ITEM_PRODUCT rli,PPA.REQUEST req where rli.REQUEST_ID=req.REQUEST_ID and req.PR_NUMBER=#REQ_ID and req.BUYER_COMPANY_ID=#BUSINESS_UNIT and rli.DELETION_MARK=1)>0
begin
print 'reached to Kunals call for the proc update items'
EXEC PPA.SP_UPDATE_ITEMS_OF_PR #REQ_ID, #BUSINESS_UNIT, #CURRENCY_CD,#REVISION_NUMBER,#REQUEST_ID,#PS_DATE_MODIFIED,#PS_DATE_CREATED, #success
end
END
-----------------------------------------------addressing issue C_42:End-------------------------------------------------------------------------
--Retrieve comments from PeopleSoft and attempt inserting them into PPA's tables
SET #success = 1
EXEC PPA.SP_INSERT_COMMENTS #REQ_ID, #BUSINESS_UNIT, #success
IF #success = 0
BEGIN
SET #Message = #MessageDescription + ': Failed to INSERT comments into PPA back-end for PR_NUMBER = ' + #REQ_ID + ' BUSINESS_UNIT = ' + #BUSINESS_UNIT
PRINT #Message
END
FETCH NEXT FROM cursor_ps_req_hdr INTO
#BUSINESS_UNIT,
#REQ_ID,
#CURRENCY_CD,
#PS_DATE_MODIFIED, -- to address issue C_42
#PS_DATE_CREATED -- to address issue C_42
END
--//Close and Deallocate the cursor
CLOSE cursor_ps_req_hdr
DEALLOCATE cursor_ps_req_hdr
PRINT #MessageDescription + ': Closed and Deallocated CURSOR cursor_ps_req_hdr'
SET #success = 1
PRINT 'Successfully exiting ' + #MessageDescription
RETURN #success
ERRORHANDLER:
PRINT #MessageDescription + ': Inside ERRORHANDLER'
IF CURSOR_STATUS('global', 'cursor_ps_req_hdr') >= 0
BEGIN
CLOSE cursor_ps_req_hdr
DEALLOCATE cursor_ps_req_hdr
PRINT #MessageDescription + ': Closed and Deallocated CURSOR cursor_ps_req_hdr'
END
SET #success = 0
--//log the message in a log file if #MessageDesc <> NULL
PRINT 'Exiting ERRORHANDLER of ' + #MessageDescription
RETURN #success
END
How to improve the performance:
Remove the cursor & RBAR (row-by-agonizing-row) style coding
If you can't remove the cursor, change it at least to fast_forward and local
There's 5 calls to different procedures. Without any details about them, they could be the reason and might need tuning
Look at execution plan & statistics io output. Focus on the operations with highest IO and scans causing lot of IO, expensive sorts, spools, key lookups with a lot of executions
Remove prints
Get someone more experienced to help you
i have construct a dynamic sql and it is bit big. so when i am trying to execute it then i am getting error like
Msg 156, Level 15, State 1, Procedure sp_InstallListenerNotification_1, Line 31
Incorrect syntax near the keyword 'END'.
Msg 102, Level 15, State 1, Procedure sp_InstallListenerNotification_1, Line 118
Incorrect syntax near 'END'.
i am not being able to find out where is the problem and where to fix. so help me to compile it if possible. here is my dynamic sql script.
DECLARE #msg VARCHAR(MAX)
DECLARE #crlf CHAR(1)
SET #crlf = CHAR(10)
SET #msg = 'Current user must have following permissions: '
SET #msg = #msg + '[CREATE PROCEDURE, CREATE SERVICE, CREATE QUEUE, SUBSCRIBE QUERY NOTIFICATIONS, CONTROL, REFERENCES] '
SET #msg = #msg + 'that are required to start query notifications. '
SET #msg = #msg + 'Grant described permissions with following script: ' + #crlf
SET #msg = #msg + 'GRANT CREATE PROCEDURE TO [<username>];' + #crlf
SET #msg = #msg + 'GRANT CREATE SERVICE TO [<username>];' + #crlf
SET #msg = #msg + 'GRANT CREATE QUEUE TO [<username>];' + #crlf
SET #msg = #msg + 'GRANT REFERENCES ON CONTRACT::[DEFAULT] TO [<username>];' + #crlf
SET #msg = #msg + 'GRANT SUBSCRIBE QUERY NOTIFICATIONS TO [<username>];' + #crlf
SET #msg = #msg + 'GRANT CONTROL ON SCHEMA::[<schemaname>] TO [<username>];'
PRINT #msg
IF OBJECT_ID ('[bba-reman].sp_InstallListenerNotification_1', 'P') IS NULL
BEGIN
EXEC ('
CREATE PROCEDURE [bba-reman].sp_InstallListenerNotification_1
AS
BEGIN
-- Service Broker configuration statement.
-- Setup Service Broker
IF EXISTS (SELECT * FROM sys.databases
WHERE name = ''bbareman'' AND (is_broker_enabled = 0 OR is_trustworthy_on = 0))
BEGIN
IF (NOT EXISTS(SELECT * FROM sys.fn_my_permissions(NULL, ''SERVER'')
WHERE permission_name = ''CONTROL SERVER''))
BEGIN
DECLARE #msg VARCHAR(MAX)
SET #msg = ''Current user doesn''''t have CONTROL SERVER permission to enable service broker. ''
SET #msg = #msg + ''Grant sufficient permissions to current user or ''
SET #msg = #msg + ''execute ALTER DATABASE [<dbname>] SET ENABLE_BROKER with admin rights.''
RAISERROR (#msg, 16, 1)
END
ELSE
BEGIN
--ALTER DATABASE [bbareman] SET SINGLE_USER WITH ROLLBACK IMMEDIATE
--ALTER DATABASE [bbareman] SET ENABLE_BROKER;
--ALTER DATABASE [bbareman] SET MULTI_USER WITH ROLLBACK IMMEDIATE
-- FOR SQL Express
--ALTER AUTHORIZATION ON DATABASE::[bbareman] TO [sa]
--ALTER DATABASE [bbareman] SET TRUSTWORTHY ON;
END
END
-- Create a queue which will hold the tracked information
IF NOT EXISTS (SELECT * FROM sys.service_queues WHERE name = ''ListenerQueue_1'')
CREATE QUEUE [bba-reman].[ListenerQueue_1]
-- Create a service on which tracked information will be sent
IF NOT EXISTS(SELECT * FROM sys.services WHERE name = ''ListenerService_1'')
CREATE SERVICE [ListenerService_1] ON QUEUE [bba-reman].[ListenerQueue_1] ([DEFAULT])
-- Notification Trigger check statement.
IF OBJECT_ID (''[bba-reman].tr_Listener_1'', ''TR'') IS NOT NULL
RETURN;
-- Notification Trigger configuration statement.
DECLARE #triggerStatement NVARCHAR(MAX)
DECLARE #select NVARCHAR(MAX)
DECLARE #sqlInserted NVARCHAR(MAX)
DECLARE #sqlDeleted NVARCHAR(MAX)
SET #triggerStatement = N''
CREATE TRIGGER [tr_Listener_1]
ON [bba-reman].[ContentChangeLog]
AFTER INSERT, UPDATE, DELETE
AS
SET NOCOUNT ON;
--Trigger ContentChangeLog is rising...
IF EXISTS (SELECT * FROM sys.services WHERE name = ''''ListenerService_1'''')
BEGIN
DECLARE #message NVARCHAR(MAX)
SET #message = N''''<root/>''''
IF ( EXISTS(SELECT 1))
BEGIN
DECLARE #retvalOUT NVARCHAR(MAX)
%inserted_select_statement%
IF (#retvalOUT IS NOT NULL)
BEGIN SET #message = N''''<root>'''' + #retvalOUT END
%deleted_select_statement%
IF (#retvalOUT IS NOT NULL)
BEGIN
IF (#message = N''''<root/>'''') BEGIN SET #message = N''''<root>'''' + #retvalOUT END
ELSE BEGIN SET #message = #message + #retvalOUT END
END
IF (#message != N''''<root/>'''') BEGIN SET #message = #message + N''''</root>'''' END
END
--Beginning of dialog...
DECLARE #ConvHandle UNIQUEIDENTIFIER
--Determine the Initiator Service, Target Service and the Contract
BEGIN DIALOG #ConvHandle
FROM SERVICE [ListenerService_1] TO SERVICE ''''ListenerService_1'''' ON CONTRACT [DEFAULT] WITH ENCRYPTION=OFF, LIFETIME = 60;
--Send the Message
SEND ON CONVERSATION #ConvHandle MESSAGE TYPE [DEFAULT] (#message);
--End conversation
END CONVERSATION #ConvHandle;
END
''
SET #select = STUFF((SELECT '','' + COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = ''ContentChangeLog'' AND TABLE_CATALOG = ''bbareman''
FOR XML PATH ('''')
), 1, 1, '''')
SET #sqlInserted =
N''SET #retvalOUT = (SELECT '' + #select + N''
FROM INSERTED
FOR XML PATH(''''row''''), ROOT (''''inserted''''))''
SET #sqlDeleted =
N''SET #retvalOUT = (SELECT '' + #select + N''
FROM DELETED
FOR XML PATH(''''row''''), ROOT (''''deleted''''))''
SET #triggerStatement = REPLACE(#triggerStatement
, ''%inserted_select_statement%'', #sqlInserted)
SET #triggerStatement = REPLACE(#triggerStatement
, ''%deleted_select_statement%'', #sqlDeleted)
EXEC sp_executeSql #triggerStatement
END
')
END
You can't have an empty BEGIN ...END block. You need to add at least one executable statement, for example a PRINT
BEGIN
--ALTER DATABASE [bbareman] SET SINGLE_USER WITH ROLLBACK IMMEDIATE
--ALTER DATABASE [bbareman] SET ENABLE_BROKER;
--ALTER DATABASE [bbareman] SET MULTI_USER WITH ROLLBACK IMMEDIATE
-- FOR SQL Express
--ALTER AUTHORIZATION ON DATABASE::[bbareman] TO [sa]
--ALTER DATABASE [bbareman] SET TRUSTWORTHY ON;
PRINT 'Dummy Output'
END
It also looks like you are missing an END. You need three END statements after the dummy PRINT.