I was working with a customer and discussing how to do error handling. This is a short post that looks at how you can start adding TRY.. CATCH blocks to your code.
Another post for me that is simple and hopefully serves as an example for people trying to get blogging as #SQLNewBloggers.
TRY CATCH
This is a common error handling technique in other languages. C# uses it, as does Java, while Python has TRY EXCEPT. There are other examples, but these are good habits to get into when you don’t know how code will behave or if there is something in your data or environment that could cause an issue.
In SQL, I think many of us get used to writing one statement in a query and forget to do error handling, or transactions. However, this can be a good habit as your code might grow and people might add more statements that should execute.
A classic example of code is someone writing this:
DECLARE @id INT = 2 , @name VARCHAR(20) = 'Voice od the DBA' , @stat INT = 1;
BEGIN TRAN;
INSERT dbo.Customer
(CustomerID, CustomerName, status)
VALUES
(@id, @name, @stat);
IF @@ERROR = 0
COMMIT;
ELSE
ROLLBACK;
Note that this does look for an error and then decide what to do. However, we could be better, especially if we wanted to possibly add a second insert or other work. We could do this:
DECLARE @id INT = 2 , @name VARCHAR(20) = 'Voice od the DBA' , @stat INT = 1;
BEGIN TRY
BEGIN TRAN;
INSERT dbo.Customer
(CustomerID, CustomerName, status)
VALUES
(@id, @name, @stat);
COMMIT
END TRY
BEGIN CATCH
ROLLBACK
END CATCH
It doesn’t look like much, but this code could easily be enhanced with a better pattern. We can capture the various error messages like this:
DECLARE @id INT = 2 , @name VARCHAR(20) = 'Voice od the DBA' , @stat INT = 1;
BEGIN TRY
BEGIN TRAN;
INSERT dbo.Customer
(CustomerID, CustomerName, status)
VALUES
(@id, @name, @stat);
COMMIT
END TRY
BEGIN CATCH
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
SELECT
@ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE();
RAISERROR (@ErrorMessage, -- Message text.
@ErrorSeverity, -- Severity.
@ErrorState -- State.
);
WHILE @@TRANCOUNT > 0
BEGIN
ROLLBACK TRANSACTION;
END
END CATCH
In this case, we have a few statements that work with the error, in this case using RAISERROR to raise this. We could also use THROW or add something else. If we had more inserts, like to a child table, we could encapsulate them all here. What’s more, if we had logging, we could log this before the rollback to another system if our logging were not transaction dependent.
Using TRY CATCH is really just structuring your code differently. Ideally, using something a snippet in SQL Prompt so your developers have an easy way to standardize error handling.
SQL New Blogger
This post took me about 15 minutes to structure and test. I looked at a few patterns, and I liked the one in this Stack Overflow answer as a good way to generically implement this structure.
You could write a similar post showing your next boss how you implement error handling, transactions, anything. Give it a try.