0% found this document useful (0 votes)
73 views

22 - Transactions and Error Handling in SQL Server

This document provides examples of using error handling, transactions, and try/catch blocks in SQL Server. It demonstrates how to add error handling to scripts using try/catch blocks, insert errors into an errors table, and return error information. Examples also show nesting try/catch blocks, using transactions with savepoints and rollback, and customizing error messages with RAISERROR and THROW.

Uploaded by

massyweb
Copyright
© © All Rights Reserved
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
73 views

22 - Transactions and Error Handling in SQL Server

This document provides examples of using error handling, transactions, and try/catch blocks in SQL Server. It demonstrates how to add error handling to scripts using try/catch blocks, insert errors into an errors table, and return error information. Examples also show nesting try/catch blocks, using transactions with savepoints and rollback, and customizing error messages with RAISERROR and THROW.

Uploaded by

massyweb
Copyright
© © All Rights Reserved
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 9

/*

Starting with error handling


*/

-- error-handling script

-- Set up the TRY block


BEGIN TRY
-- Add the constraint
ALTER TABLE products
ADD CONSTRAINT CHK_Stock CHECK (stock >= 0);
END TRY
-- Set up the CATCH block
BEGIN CATCH
SELECT 'An error occurred!';
END CATCH

-- Nesting TRY...CATCH constructs

-- Set up the first TRY block


BEGIN TRY
INSERT INTO buyers (first_name, last_name, email, phone)
VALUES ('Peter', 'Thompson', '[email protected]', '555000100');
END TRY
-- Set up the first CATCH block
BEGIN CATCH
SELECT 'An error occurred inserting the buyer! You are in the first CATCH
block';
-- Set up the nested TRY block
BEGIN TRY
INSERT INTO errors
VALUES ('Error inserting a buyer');
SELECT 'Error inserted correctly!';
END TRY
-- Set up the nested CATCH block
BEGIN CATCH
SELECT 'An error occurred inserting the error! You are in the nested CATCH
block';
END CATCH
END CATCH

-- Correcting compilation errors

BEGIN TRY
INSERT INTO products (product_name, stock, price)
VALUES ('Sun Bicycles ElectroLite - 2017', 10, 1559.99);
END TRY
BEGIN CATCH
SELECT 'An error occurred inserting the product!';
BEGIN TRY
INSERT INTO errors
VALUES ('Error inserting a product');
END TRY
BEGIN CATCH
SELECT 'An error occurred inserting the error!';
END CATCH
END CATCH
-- Using error functions

-- Set up the TRY block


BEGIN TRY
SELECT 'Total: ' + SUM(price * quantity) AS total
FROM orders
END TRY
-- Set up the CATCH block
BEGIN CATCH
-- Show error information.
SELECT ERROR_NUMBER() AS number,
ERROR_SEVERITY() AS severity_level,
ERROR_STATE() AS state,
ERROR_LINE() AS line,
ERROR_MESSAGE() AS message;
END CATCH

-- Using error functions in a nested TRY...CATCH

BEGIN TRY
INSERT INTO products (product_name, stock, price)
VALUES ('Trek Powerfly 5 - 2018', 2, 3499.99),
('New Power K- 2018', 3, 1999.99)
END TRY
-- Set up the outer CATCH block
BEGIN CATCH
SELECT 'An error occurred inserting the product!';
-- Set up the inner TRY block
BEGIN TRY
-- Insert the error
INSERT INTO errore
VALUES ('Error inserting a product');
END TRY
-- Set up the inner CATCH block
BEGIN CATCH
-- Show number and message error
SELECT
ERROR_LINE() AS line,
ERROR_MESSAGE() AS message;
END CATCH
END CATCH

/*
Raising, throwing and customizing your errors
*/

-- CATCHING the RAISERROR

BEGIN TRY
DECLARE @product_id INT = 5;
IF NOT EXISTS (SELECT * FROM products WHERE product_id = @product_id)
RAISERROR('No product with id %d.', 11, 1, @product_id);
ELSE
SELECT * FROM products WHERE product_id = @product_id;
END TRY
-- Catch the error
BEGIN CATCH
-- Select the error message
SELECT ERROR_MESSAGE();
END CATCH

-- THROW without parameters

CREATE PROCEDURE insert_product


@product_name VARCHAR(50),
@stock INT,
@price DECIMAL

AS

BEGIN TRY
INSERT INTO products (product_name, stock, price)
VALUES (@product_name, @stock, @price);
END TRY
-- Set up the CATCH block
BEGIN CATCH
-- Insert the error and end the statement with a semicolon
INSERT INTO errors VALUES ('Error inserting a product');
-- Re-throw the error
THROW;
END CATCH

-- Executing a stored procedure that throws an error

BEGIN TRY
-- Execute the stored procedure
EXEC insert_product
-- Set the values for the parameters
@product_name = 'Super bike',
@stock = 3,
@price = 499.99;
END TRY
-- Set up the CATCH block
BEGIN CATCH
-- Select the error message
SELECT error_message();
END CATCH

-- THROW with parameters

-- Set @staff_id to 4
DECLARE @staff_id INT = 4;

IF NOT EXISTS (SELECT * FROM staff WHERE staff_id = @staff_id)


-- Invoke the THROW statement with parameters
THROW 50001 , 'No staff member with such id', 1;
ELSE
SELECT * FROM staff WHERE staff_id = @staff_id
-- Concatenating the message

-- Set @first_name to 'Pedro'


DECLARE @first_name NVARCHAR(20) = 'Pedro';
-- Concat the message
DECLARE @my_message NVARCHAR(500) =
CONCAT('There is no staff member with ', @first_name, ' as the first name.');

IF NOT EXISTS (SELECT * FROM staff WHERE first_name = @first_name)


-- Throw the error
THROW 50000, @my_message, 1;

-- FORMATMESSAGE with message string

DECLARE @product_name AS NVARCHAR(50) = 'Trek CrossRip+ - 2018';


DECLARE @number_of_sold_bikes AS INT = 10;
DECLARE @current_stock INT;
-- Select the current stock
SELECT @current_stock = stock FROM products WHERE product_name = @product_name;
DECLARE @my_message NVARCHAR(500) =
-- Customize the message
FORMATMESSAGE('There are not enough %s bikes. You only have %d in stock.',
@product_name, @current_stock);

IF (@current_stock - @number_of_sold_bikes < 0)


-- Throw the error
THROW 50000, @my_message, 1;

-- FORMATMESSAGE with message number

EXEC sp_addmessage @msgnum = 50002, @severity = 16, @msgtext = 'There are not
enough %s bikes. You only have %d in stock.', @lang = N'us_english';

DECLARE @product_name AS NVARCHAR(50) = 'Trek CrossRip+ - 2018';


DECLARE @sold_bikes AS INT = 100;
DECLARE @current_stock INT;

SELECT @current_stock = stock FROM products WHERE product_name = @product_name;

DECLARE @my_message NVARCHAR(500) =


FORMATMESSAGE(50002, @product_name, @current_stock);

IF (@current_stock - @sold_bikes < 0)


THROW 50000, @my_message, 1;

-- FORMATMESSAGE with message number


EXEC sp_addmessage @msgnum = 50002, @severity = 16, @msgtext = 'There are not
enough %s bikes. You only have %d in stock.', @lang = N'us_english';

DECLARE @product_name AS NVARCHAR(50) = 'Trek CrossRip+ - 2018';


DECLARE @sold_bikes AS INT = 10;
DECLARE @current_stock INT;

SELECT @current_stock = stock FROM products WHERE product_name = @product_name;


DECLARE @my_message NVARCHAR(500) =
FORMATMESSAGE(50002, @product_name, @current_stock);

IF (@current_stock - @sold_bikes < 0)


THROW 50000, @my_message, 1;

/*
Transactions in SQL Server
*/

-- Correcting a transaction

BEGIN TRY
begin TRAN
UPDATE accounts SET current_balance = current_balance - 100 WHERE
account_id = 1;
INSERT INTO transactions VALUES (1, -100, GETDATE());

UPDATE accounts SET current_balance = current_balance + 100 WHERE


account_id = 5;
INSERT INTO transactions VALUES (5, 100, GETDATE());
commit TRAN
END TRY
begin CATCH
rollback TRAN
END CATCH

-- Rolling back a transaction if there is an error

BEGIN TRY
-- Begin the transaction
BEGIN transaction;
UPDATE accounts SET current_balance = current_balance - 100 WHERE
account_id = 1;
INSERT INTO transactions VALUES (1, -100, GETDATE());

UPDATE accounts SET current_balance = current_balance + 100 WHERE


account_id = 5;
-- Correct it
INSERT INTO transactions VALUES (500, 100, GETDATE());
-- Commit the transaction
commit TRAN;
END TRY
BEGIN CATCH
SELECT 'Rolling back the transaction';
-- Rollback the transaction
rollback;
END CATCH

-- Choosing when to commit or rollback a transaction

-- Begin the transaction


begin transaction;
UPDATE accounts set current_balance = current_balance + 100
WHERE current_balance < 5000;
-- Check number of affected rows
IF @@ROWCOUNT > 200
BEGIN
-- Rollback the transaction
rollback;
SELECT 'More accounts than expected. Rolling back';
END
ELSE
BEGIN
-- Commit the transaction
commit;
SELECT 'Updates commited';
END

-- Checking @@TRANCOUNT in a TRY...CATCH construct

BEGIN TRY
-- Begin the transaction
BEGIN TRAN;
-- Correct the mistake
UPDATE accounts SET current_balance = current_balance + 200
WHERE account_id = 10;
-- Check if there is a transaction
IF @@TRANCOUNT > 0
-- Commit the transaction
COMMIT TRAN;

SELECT * FROM accounts


WHERE account_id = 10;
END TRY
BEGIN CATCH
SELECT 'Rolling back the transaction';
-- Check if there is a transaction
IF @@TRANCOUNT > 0
-- Rollback the transaction
ROLLBACK TRAN;
END CATCH

-- Using savepoints

BEGIN TRAN;
-- Mark savepoint1
SAVE TRAN savepoint1;
INSERT INTO customers VALUES ('Mark', 'Davis', '[email protected]',
'555909090');

-- Mark savepoint2
SAVE TRAN savepoint2;
INSERT INTO customers VALUES ('Zack', 'Roberts', '[email protected]',
'555919191');

-- Rollback savepoint2
ROLLBACK TRAN savepoint2;
-- Rollback savepoint1
ROLLBACK TRAN savepoint1;
-- Mark savepoint3
SAVE TRAN savepoint3;
INSERT INTO customers VALUES ('Jeremy', 'Johnsson',
'[email protected]', '555929292');
-- Commit the transaction
COMMIT TRAN;

-- XACT_ABORT and THROW

-- Use the appropriate setting


SET XACT_ABORT ON;
-- Begin the transaction
BEGIN TRAN;
UPDATE accounts set current_balance = current_balance - current_balance *
0.01 / 100
WHERE current_balance > 5000000;
IF @@ROWCOUNT <= 10
-- Throw the error
THROW 55000, 'Not enough wealthy customers!', 1;
ELSE
-- Commit the transaction
COMMIT TRAN;

-- Doomed transactions

-- Use the appropriate setting


SET XACT_ABORT ON;
BEGIN TRY
BEGIN TRAN;
INSERT INTO customers VALUES ('Mark', 'Davis', '[email protected]',
'555909090');
INSERT INTO customers VALUES ('Dylan', 'Smith', '[email protected]',
'555888999');
COMMIT TRAN;
END TRY
BEGIN CATCH
-- Check if there is an open transaction
IF XACT_STATE() <> 0
-- Rollback the transaction
ROLLBACK TRAN;
-- Select the message of the error
SELECT ERROR_MESSAGE() AS Error_message;
END CATCH

/*
Controlling the concurrency: Transaction isolation levels
*/

-- Using the READ UNCOMMITTED isolation level

-- Set the appropriate isolation level


SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

-- Select first_name, last_name, email and phone


SELECT
first_name,
last_name,
email,
phone
FROM customers;

-- Prevent dirty reads

-- Set the appropriate isolation level


SET transaction isolation level read committed

-- Count the accounts


SELECT count(*) AS number_of_accounts
FROM accounts
WHERE current_balance >= 50000;

-- Preventing non-repeatable reads

-- Set the appropriate isolation level


set transaction isolation level repeatable read

-- Begin a transaction
begin tran

SELECT * FROM customers;

-- some mathematical operations, don't care about them...

SELECT * FROM customers;

-- Commit the transaction


commit tran

-- Prevent phantom reads in a table

-- Set the appropriate isolation level


set transaction isolation level serializable

-- Begin a transaction
begin tran

SELECT * FROM customers;

-- After some mathematical operations, we selected information from the customers


table.
SELECT * FROM customers;

-- Commit the transaction


commit tran

-- Prevent phantom reads just in some rows

-- Set the appropriate isolation level


set transaction isolation level serializable
-- Begin a transaction
begin tran

-- Select customer_id between 1 and 10


SELECT *
FROM customers
where customer_id between 1 AND 10;

-- After completing some mathematical operation, select customer_id between 1 and


10
SELECT *
FROM customers
where customer_id between 1 AND 10;

-- Commit the transaction


commit tran

-- Avoid being blocked

SELECT *
-- Avoid being blocked
FROM transactions with (nolock)
WHERE account_id = 1

You might also like