Terminating a job in SQL Server during runtime - sql

Is there a way to make a scheduled job terminate (stop, quit, stop executing, report failure) within a stored procedure in that job?
For example, I have some check queries within a TRY block that do RAISERROR (59834,16,1) to go to the CATCH block to send an email saying that the check queries found a bad situation and the job must stop. The number 59834 was arbitrary but specific.
However, every time I test the job, even though I raised an error, the job continues to execute; it never reports a failure.
I have tried using the same RAISERROR in the CATCH block as I did in the TRY block, but that did not work either.
I want the job to stop in this once instance, it will run every day.

It sounds like the XACT_ABORT setting is not on. Without XACT_ABORT on, the execution will continue regardless of any errors encountered. More information about XACT_ABORT:
Microsoft BOL entry for XACT_ABORT
What is the benefit of using SET XACT_ABORT ON in a stored procedure?
So you might consider a SET XACT_ABORT ON at the start of the job.

Related

Is a ROLLBACK TRANSACTION statement necessary

When opening an explicit transaction if a failure occurs will all statements between the BEGIN and COMMIT automatically be rolled back? Or do you have to issue a ROLLBACK statement.
In my previous experience everything between the BEGIN and COMMIT automatically rolled back. Therefore what constitutes when you need to issue a ROLLBACK statement to manually roll it back?
It depends upon your session settings and the type of error. If it is a statement-terminating error, then the transaction just continues with the next statement. If it's a batch-terminating error, then the transaction is aborted.
To avoid issues with statement-terminating errors, make sure you have previously executed:
SET XACT_ABORT ON;
and then all statement-terminating errors will also abort the transaction and roll back.
Some programming client libraries turn that on automatically for you, and that's why you may have previously seen the auto-rollback, but I usually add it as the first line of all my stored procedures, just to be sure.

Is there a SQL equivalent of return?

Consider the following bit of SQL
SET DATEFORMAT ymd
SET ARITHABORT, ANSI_PADDING, ANSI_WARNINGS, CONCAT_NULL_YIELDS_NULL, QUOTED_IDENTIFIER, ANSI_NULLS, NOCOUNT ON
SET NUMERIC_ROUNDABORT, IMPLICIT_TRANSACTIONS, XACT_ABORT OFF
GO
USE master
GO
IF DB_NAME() <> N'master' SET NOEXEC ON
--
-- Create database [myDatabaseName]
--
PRINT (N'Create database [myDatabaseName]')
GO
CREATE DATABASE myDatabaseName
There is then a very long script setting up tables, views, stored procedures etc etc.
I would like to know if SQL would allow something along the likes of the following pseudo code;
If (myDatabaseName Exists)
Return // in other word abort the script here but don't throw an error
Else
//Carry on and install the database
I am aware of the Exists function in SQL but I can't seem to find anything that would simply abort the remains of the script straightaway.
This script will end up in an installation routine. In theory it should never be in an installer where the database is already present, however I would prefer not to take chances and prepare properly for a potential mistake. It is also crucial that the script does not throw any error as that will just cause the installer to roll back and install nothing.
I'm hoping that something exists in SQL that will just exit a script cleanly if particular conditions are met. By exit I really do mean exit as opposed to simply breaking out of the condition being currently evaluated.
The problem is, your client tool (SSMS, SQLCMd, etc) splits your script into batches based on the location of the GO keyword (it's a client tool thing, not SQL Server at all).
It then sends the first batch. After the first batch is complete (no matter what the outcome), it sends the second batch, then the third after the second, etc.
If you're running with sufficient permissions, a high-valued RAISERROR (severity 20-25) should stop the client tool in its tracks (because it forces the connection closed). It's not that clean though.
Another option is to try to set NOEXEC ON which still does some work with each subsequent batch (compilation) but won't run any of the code1. This allows you a slightly better recovery option if you want some batches at the end to always run, by turning it OFF again.
1Which means you still will see error messages for compilation errors for later batches which rely upon database structures that would have been created in earlier batches, if they weren't being skipped.
You can use GOTO as follows :
If (myDatabaseName Exists)
GOTO QUIT; // in other word abort the script here but don't throw an error
Else
//Carry on and install the database
QUIT:
SELECT 0;
There are several methods for that kind of request :
raiserror('Oh no a fatal error', 20, -1) with log
OR
print 'Fatal error, script will not continue!'
set noexec on
They should work and close the connection.
See here : Answer

Are T-SQL rollbacks deterministic or garbage collected?

In our Miscrosoft Sql Server 2008 database, I found some stored procedures that do this:
BEGIN TRY
BEGIN TRANSACTION
query1
query2
query3
COMMIT TRANSACTION
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
RAISERROR
END CATCH
I said to my coworker that this is functionally identical to this:
BEGIN TRANSACTION
query1
query2
query3
COMMIT TRANSACTION
If, say, query2 fails, you never hit the COMMIT line, so of course SqlServer rolls back, and because of the error, it throws it back to the client as well. Since the CATCH block does the same thing as the default, I argued that we don't need the TRY/CATCH block at all.
My co-worker agrees that the ROLLBACK will happen eventually, but it could be some time later, and could hold resources or lock records for some non-deterministic amount of time, and this could cause problems.
So my question is: if a stored procedure fails in a transaction, when does that transaction get rolled back?
The rollback won't be triggered with your solution in the expected way.
You have to add
set xact_abort on
to your query.
For further information see an old answer and the Microsoft documentation
SQL Server will happily leave the transaction open forever as long as the client connection remains open. An explicit rollback is a good practice in that it doesn't wait for the client connection to be physically closed or the pooled connection reused. A simple THROW (SQL 2012 and later) in the CATCH block will rollback the transaction and raise the error.
I recommend the SET XACT_ABORT ON option hash suggested to mitigate a another issue. If a client timeout occurs during query execution, no further code in the batch (including the ROLLBACK) will execute and the transaction will be left open. However, the transaction will still get rolled back with SET XACT_ABORT ON.

Prevent a sql trigger from rolling back original transaction on error

In Sql Server 2008 I've been asked to write triggers to do various types of logging in an application I've built. The problem is my SQL is rusty and sometimes some of the things I put in the triggers to do logging will unexpectedly error out. I intend to eventually work out all the errors but in the meantime my trigger code is breaking my application because if the trigger unexpectedly fails it rolls back the update or insert that triggered it breaking pieces of the application. I attempted to put a try catch block around the trigger code but it appears that doesn't do what I'm accustomed to it doing in other languages and it will rollback the original transaction even with that.
Does anybody know how/if you can write a trigger that when it errors it just dies gracefully and lets the transaction that triggered it complete?
You can enclose your trigger body code into a try-catch block.
CREATE TRIGGER tg
ON tt
AFTER DELETE
AS
set xact_abort off;
BEGIN TRY
sql_statements
END TRY
BEGIN CATCH
dies gracefully
END CATCH;
Remember to set xact_abort to off to avoid automatically rolling back current transaction.
sql fiddle sample

How to get inner errors from try/catch clause in SQL Server

I am running a stored procedure in SQL Server 2008 inside a try/catch. The stored procedure and the stored procs it calls raise a few errors but in the try/catch you only get the last error from the stored procedure that you are running.
Is there a way/trick to be able to somehow catch ALL the errors generated by child stored proc calls while running a particular stored procedure? (assume that you have no access to any stored procedures so you can't modify where they can write the error, i.e. you can't just change all the stored procedures to stop raising errors and instead write them to some table and in your catch read from that table)
Here is a good resource for how to deal with error handling in SQL Server.
http://www.sqlservercentral.com/articles/Development/anerrorhandlingtemplatefor2005/2295/
However, some of the methods require that you have the ability to change the code in order to capture the errors. There is really no way of getting around this. You can't just ignore the error, keep processing, and then come around later to deal with the error. In most, if not all, languages, exceptions have to be dealt with at the time the exception was raised. T-SQL is no different.
I personally use a stored procedure to log any error whenever it occurs. Here is what I use:
CREATE PROCEDURE [dbo].[Error_Handler]
#returnMessage bit = 'False'
WITH EXEC AS CALLER
AS
BEGIN
INSERT INTO Errors (Number,Severity,State,[Procedure],Line,[Message])
VALUES (
ERROR_NUMBER(),
ERROR_SEVERITY(),
ERROR_STATE(),
isnull(ERROR_PROCEDURE(),'Ad-Hoc Query'),
isnull(ERROR_LINE(),0),
ERROR_MESSAGE())
IF(#returnMessage = 'True')
BEGIN
select Number,Severity,State,[Procedure],Line,[Message]
from Errors
where ErrorID = scope_identity()
END
END
If you have stored procs that are raising more than one error, they need to be replaced no matter what. You probably have data integrity errors in your database. That is a critical, "everything needs to stop right now until this is fixed" kind of issue. If you can't replace them and they were incorrectly written to allow processing to continue when an error was reached, then I know of no way to find the errors. Errors are not recorded unless you tell them to be recorded. If the stored procs belong to a product you bought from another vendor and that's why you can't change them, your best bet is to change to a vendor that actually understands how to program database code because there is no salvaging a product written that badly.
You wouldn't have a Java or c# methods raising error after error. Why do you expect SQL to allow this? An exception is an exception
If the DB Engine is throwing errors then you have problems.
What I've done before is to separate testing and checking code: find out what is wronf first and throw one exception If no errors, do your writes.