I'm trying to write a script that will exit as an error when there are currently SQL agent jobs running. I would also like it to succeed (exit 0) if there are no jobs running.
Something like below.
IF
EXEC msdb.dbo.sp_help_job #execution_status=1
THEN
RAISE ERROR
ELSE
COMPILE SUCCESS
The following code will help you. You may need to change the code for your required action.
First, you need to create a Stored Procedure:
CREATE PROCEDURE YourProc
AS
BEGIN
DECLARE #ErrMsg NVARCHAR(MAX), #ErrSeverity INT
SET XACT_ABORT OFF
BEGIN TRY
IF EXISTS (
SELECT *
FROM msdb.dbo.sysjobs_view job
INNER JOIN msdb.dbo.sysjobactivity activity
ON job.job_id = activity.job_id
WHERE activity.run_Requested_date IS NOT NULL
AND activity.stop_execution_date IS NULL)
BEGIN
SELECT #ErrMsg = 'There is a Job already running',
#ErrSeverity = 1;
RAISERROR (#ErrMsg, #ErrSeverity, 1);
END
ELSE
PRINT 'No Jobs running'
END TRY
BEGIN CATCH
SELECT #ErrMsg = ERROR_MESSAGE(),
#ErrSeverity = ERROR_SEVERITY();
RAISERROR (#ErrMsg, #ErrSeverity, 1);
END CATCH
END
Then, you can call your procedure:
EXEC YourProc
Related
I have one procedure with multiple internal procedures. The main procedure is with try-catch block and transaction in while expression. Each of the internal procedures has no transaction and no try-catch block.
My question is if procedure3 crashes with an error, will the whole transaction be rolled back and procedure1 and procedure2 will not have executed? In this case what will XACT_STATE() do?
It looks like that:
DECLARE #param int;
CREATE TABLE #table (id int);
INSERT INTO #table (id)
SELECT SubmissionDataID
FROM [sob].[SubmissionData]
WHERE [sob].[SubmissionData].SubmissionStatusID = 9
AND [sob].[SubmissionData].[IsLast] = 1;
WHILE EXISTS (SELECT TOP 1 id FROM #table)
BEGIN
BEGIN TRY
BEGIN TRANSACTION
SELECT TOP 1 #param=id FROM #table
EXEC procedure1 (#param);
EXEC procedure2 (#param);
EXEC procedure3 (#param);
EXEC procedure4 (#param);
EXEC procedure5 (#param);
EXEC procedure6 (#param);
EXEC procedure7 (#param);
DELETE FROM #table
WHERE id = #param
COMMIT TRANSACTION
END TRY
BEGIN CATCH
DELETE FROM #table
WHERE id = #param;
SELECT
ERROR_MESSAGE(), ERROR_SEVERITY(), ERROR_STATE();
-- Transaction uncommittable
IF (XACT_STATE()) = -1
BEGIN
ROLLBACK TRANSACTION
PRINT 'INFO: TRANSACTION has been ROLLBACKED!';
THROW;
END
-- Transaction committable
IF (XACT_STATE()) = 1
COMMIT TRANSACTION
END CATCH
END --end while
DROP TABLE #table;
END
/* ************ END OF PROCEDURE ************ */
I'm not sure how XACT_STATE() works.
I have a trigger on a table that executes a stored procedure. The executed stored procedure has a TRY/CATCH, so that if there is an error, a row is inserted into a log table.
When the stored procedure fails, I'm getting the following error:
The current transaction cannot be committed and cannot support operations that write to the log file. Roll back the transaction.
How do I make it so the update get committed and the CATCH in the stored procedure is also executed? If I add:
IF ##TRANCOUNT > 0
ROLLBACK TRAN
to the stored procedure, then I get the following error:
The transaction ended in the trigger. The batch has been aborted.
Trigger:
ALTER TRIGGER [dbo].[trigger123] ON [dbo].[tbl321]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
IF UPDATE (status)
BEGIN
IF EXISTS (--some condition)
BEGIN
EXEC SProc
END
END
END
SProc:
ALTER PROCEDURE [dbo].[SProc ]
AS
BEGIN
DECLARE #ErrorMessage NVARCHAR(4000);
DECLARE #ErrorSeverity INT;
DECLARE #ErrorState INT;
BEGIN TRY
select #sql = '
declare #error1 varchar(255),
#error2 varchar(255),
#error3 varchar(255)
Exec SomeDB.DBO.ConfirmStatus ''A10594'',#error1 output,#error2 output,#error3 output
if ISNULL(#error1,0) <> 0
begin
set #error1 = ISNULL(#error2,'''') + '' '' + ISNULL(#error3,'''') + '' '' + ISNULL(#error1,0)
RAISERROR (#error1, 16, 1)
end'
from jobs j
exec(#sql) at [linked_server]
update status
set status_prev = 1
END TRY
BEGIN CATCH
SELECT
#ErrorMessage = ERROR_MESSAGE(),
#ErrorSeverity = ERROR_SEVERITY(),
#ErrorState = ERROR_STATE()
INSERT INTO error_log (error_datetime, [error_message])
SELECT
GETDATE(),
'Msg: ' + ISNULL(CONVERT(VARCHAR, ERROR_NUMBER()), 'N/A') + ', Level: ' + ISNULL(CONVERT(VARCHAR, #ErrorSeverity), 'N/A') + ', Line: ' + ISNULL(CONVERT(VARCHAR, ERROR_LINE()), 'N/A') + ', Error: ' + ISNULL(#ErrorMessage, 'N/A')
END CATCH
END
I was able to modify my stored procedure to not use a try/catch. This gets me what I need.
ALTER PROCEDURE [dbo].[SProc ]
AS
BEGIN
DECLARE #error table (error1 varchar(255))
DECLARE #ErrorMessage NVARCHAR(4000);
DECLARE #ErrorSeverity INT;
DECLARE #ErrorState INT;
BEGIN TRY
select #sql = '
declare #error1 varchar(255),
#error2 varchar(255),
#error3 varchar(255)
Exec SomeDB.DBO.ConfirmStatus ''A10594'',#error1 output,#error2 output,#error3 output
if ISNULL(#error1,0) <> 0
begin
set #error1 = ISNULL(#error2,'''') + '' '' + ISNULL(#error3,'''') + '' '' + ISNULL(#error1,0)
select #error1
end'
from jobs j
insert into #error
exec(#sql) at [linked_server]
if exists (select top 1 error1 from #error)
begin
INSERT INTO error_log (error_datetime, [error_message])
SELECT
GETDATE(),
(select top 1 error1 from #error)
else
update status
set status_prev = 1
END
I have this stored procedure, which works if I execute manually. But sometimes I see timeout exception on running this Stored Procedure. Is this is due to MERGE, http://www.mssqltips.com/sqlservertip/3074/use-caution-with-sql-servers-merge-statement/
ALTER PROCEDURE [dbo].[InsertOrUpdateMobileUser]
(
#ID BIGINT
,#Name NVARCHAR(255)
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #TranCount INT;
SET #TranCount = ##TRANCOUNT;
BEGIN TRY
IF #TranCount = 0
BEGIN TRANSACTION
ELSE
SAVE TRANSACTION InsertOrUpdateMobileUser;
MERGE INTO MobileUsers MU
USING (SELECT #ID AS ID) T ON (MU.ID = T.ID)
WHEN MATCHED THEN
UPDATE SET [Name] = CASE WHEN #Name IS NULL OR #Name = '' THEN [Name] ELSE #Name END
WHEN NOT MATCHED THEN
INSERT ([Name])
VALUES (#Name)
SELECT *
FROM MobileUsers
WHERE ID = #ID;
LBEXIT:
IF #TranCount = 0
COMMIT;
END TRY
BEGIN CATCH
DECLARE #Error INT, #Message VARCHAR(4000), #XState INT;
SELECT #Error = ERROR_NUMBER() ,#Message = ERROR_MESSAGE() ,#XState = XACT_STATE();
IF #XState = -1
ROLLBACK;
IF #XState = 1 AND #TranCount = 0
rollback
IF #XState = 1 AND #TranCount > 0
ROLLBACK TRANSACTION InsertOrUpdateMobileUser;
RAISERROR ('InsertOrUpdateMobileUser: %d: %s', 16, 1, #error, #message) ;
END CATCH
END
You differentiate between two execution methods. What are they, exactly? You mean that it works if run only the code of the procedure, and doesn't work when you EXECUTE the proc? Of it works through EXECUTE, and fails in a job?
Timeouts only concern client applications. You have SqlCommand .CommandTimeout property in .NET, and in Management Studio there's Tools>Options>Query Execution>Command Timeout. If you have a job, then it should run infinitely, there's even no option to set the timeout in Sql Server Agent.
I have a script to update my database for a new release of my web app . In this update i need to alter a strored procedure. I have an ALTER PROCEDURE script that works fine when run on its own, however when I drop it into my update script and run it I get the errors "Incorrect syntax near the keyword 'PROCEDURE'." and "Must declare the scalar variable "#age"." What am I doing wrong here? The script is as follows:
BEGIN TRY
BEGIN TRANSACTION
-- ==================================================================
-- v0.1 to v0.2
-- ==================================================================
IF EXISTS
(
SELECT * FROM SystemParameters WHERE Name = 'Version' AND Value = '0.1'
)
BEGIN
-- ==============================================================
-- Changed Stored Procedures
-- ==============================================================
ALTER PROCEDURE ClearCache
#age int = 120
AS
BEGIN
DECLARE #timestamp DATETIME
SELECT #timestamp = DATEADD(MINUTE, -#age, GETDATE())
-- Clear old searches
END
-- ==============================================================
-- Update the Version Number
-- ==============================================================
UPDATE SystemParameters SET Value = '0.2' WHERE Name = 'Version'
END
COMMIT TRANSACTION
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
-- Report the Error
DECLARE #ErrorMessage NVARCHAR(4000);
DECLARE #ErrorSeverity INT;
DECLARE #ErrorState INT;
SELECT
#ErrorMessage = ERROR_MESSAGE(),
#ErrorSeverity = ERROR_SEVERITY(),
#ErrorState = ERROR_STATE();
RAISERROR (#ErrorMessage, #ErrorSeverity, #ErrorState)
END CATCH
Any help would be appreciated :)
I doubt you can alter the procedure inside the IF clause
Try using it as a dynamic SQL
EXEC
(
'ALTER PROCEDURE ClearCache
#age int = 120
AS
BEGIN
DECLARE #timestamp DATETIME
SELECT #timestamp = DATEADD(MINUTE, -#age, GETDATE())
-- Clear old searches
END
'
)
OK, I am not that experienced with SQL 2005 error handling and am
learning my way around try/catch statements.
I have written the below procedure but no matter what I pass to it,
there is never any data in my ErrorLog table. I have passed all INT
values, all datetime values, or data strings that are not in the DB
and get '0 rows effected' with nothing reported in ErrorLog. It is
as if the CATCH statement is never reached (for what it is worth, I
have also tried commenting out the validation at the top).
Any ideas what I am doing wrong? Thanks.
ALTER PROCEDURE [dbo].[aspnet_Membership_UpdateLastActivityDate]
#UserId nvarchar(256),
#UserName nvarchar(256),
#LastActivityDate datetime,
#ApplicationName nvarchar(256)
AS
DECLARE #Today DATETIME
DECLARE #MSG VARCHAR(255)
DECLARE #Severity INT
DECLARE #ErrorCode INT
BEGIN
SET XACT_ABORT ON -- (I have also tried it without XACT_ABORT. No difference)
BEGIN TRY
SET #ErrorCode = 0
SELECT #Today = GetDate()
IF (#UserId IS NULL)
RETURN(1)
IF (#UserName IS NULL)
RETURN(1)
IF (#LastActivityDate IS NULL)
RETURN(1)
BEGIN TRAN
UPDATE dbo.aspnet_Users WITH (ROWLOCK)
SET LastActivityDate = #LastActivityDate
FROM dbo.aspnet_Users u
INNER JOIN dbo.aspnet_Applications a
ON u.ApplicationId = a.ApplicationId
WHERE u.UserName = #UserName
AND u.UserId = #UserId
AND a.ApplicationName = #ApplicationName
COMMIT TRAN
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK TRAN
SET #ErrorCode = Error_Number()
SET #Severity = Error_Severity()
SET #MSG = 'An error was thrown: '
+ 'Error(' + #ErrorCode + '):' + ERROR_MESSAGE()
+ ' Severity = ' + ERROR_SEVERITY()
+ ' State = ' + ERROR_STATE()
+ ' Procedure = ' + ERROR_PROCEDURE()
+ ' Line Number = ' + ERROR_LINE()
INSERT INTO [dbo].[ErrorLog]([errornum], [errortype], [errormsg],[errorsource], [errordate])
VALUES (#ErrorCode, 'E', #MSG, Error_Procedure(), #Today)
RAISERROR(#MSG, #Severity, 2)
END CATCH
END
RETURN #ErrorCode
It has been awhile since I've done a lot with SQL Error handling but I don't see any place that is likely to generate an error. Are you expecting the "Return" statements to be "Caught"? That isn't going to happen...they'll just return from the function. You'll need to raise an error, not trigger a Return.
Agreed with #Mark. Try changing this:
IF (#UserId IS NULL)
RETURN(1)
To this:
IF (#UserId IS NULL)
BEGIN
RAISERROR('No UserID was passed in.', 11, 1);
RETURN 1;
END
Also see this article for a fantastic error handling primer by Erland Sommarskog:
http://www.sommarskog.se/error_handling_2005.html