In this workshop you'll learn how to create and use a Stored Procedure to reuse pieces of code.
- A running copy of database xtreme;
Lately a lot of our suppliers
are going bankrupt, therefore we'd like to delete all orders
which contains products
of a given supplier
.
- Create a new stored procedure called
DeleteOrdersFromSupplier
which deletes allorders
that contain aproduct
of a given supplier. - If the stored procedure already exists, change or delete it first.
- Return the number of deleted orders as an output parameter.
Make sure the following code can be executed:
BEGIN TRANSACTION
-- Arrange
DECLARE @supplierid int,
@nrdeletedorders int
SET @supplierid = 7
-- ACT
EXECUTE DeleteOrdersFromSupplier
@supplierid, @nrdeletedorders OUTPUT
-- PRINT
print 'Amount of orders deleted for supplier ' + ltrim(str(@supplierid)) + ' = ' + ltrim(str(@nrdeletedorders))
ROLLBACK
Chances are that your code will fail to delete the orders, why? A solution will be provided in the chapter about
Cursors
.
- Ask yourself what the use case of this exercise is.
- Look at the data/tables which are needed for the use case
- Write out the code that is needed to complete the use case.
- You'll need a subquery to get all the
orders
. - Delete the
orders
based on the results from the subquery.
- You'll need a subquery to get all the
- Wrap the use case inside a stored procedure
- Why is your code failing? A solution will be provided in chapter about
Cursors
. - What is the difference between a
Stored Procedure
and aUser Defined Function
? - Is it possible to mutate data inside a function?
- Can you
EXECUTE
/EXEC
aStored Procedure
inside aFunction
?
A possible solution of exercise 1 can be found here
We'd like to clean-up the product
table since a lot of products
are no longer present in our inventory. However... we have to make sure we don't delete products
if they're already purchased
or ordered
for historical reasons.
- Create a stored procedure called
DeleteProduct1
for deleting a product. You can only delete a product if- The
product
exists - There are no
purchases
for theproduct
- There are no
orders
for theproduct
- Check these conditions before deleting the product, so you don’t rely on SQL Server messages. Generate an appropriate error message if the product can’t be deleted.
- Use
RAISERROR
orTHROW
(see Deep Dive further in this document)- It's better to fail immediatly and show the error when something goes wrong as soon as possible and stop the execution of the stored procedure. (also known as Defensive Programming).
- The
- Create a stored procedure called
DeleteProduct2
(similar toDeleteProduct1
) for deleting a product. You can only delete a product if:- The
product
exists - There are no
purchases
for theproduct
- There are no
orders
for theproduct
- In this version version you try to delete the product and catch the exeptions that might occur inside the stored procedure and
PRINT
a message to the console.
- The
- Test your procedures. Give the
SELECT
statements to find appropriate test data.
Make sure the following code can be executed:
-- Version 1
BEGIN TRANSACTION
EXECUTE deleteproduct1 403000; --Another ID might be needed.
ROLLBACK
-- Version 2
BEGIN TRANSACTION
EXECUTE deleteproduct2 403000; --Another ID might be needed.
ROLLBACK
- Version 1
- First check and then
DELETE
- What are the SELECT statements to check if :
- The
product
exists - There are no
purchases
for theproduct
- There are no
orders
for theproduct
- The
- First check and then
- Version 2
- First try to
DELETE
and then check theERROR_NUMBER()
.
Raises an exception and transfers execution to a CATCH block of a TRY...CATCH construct, or stops the execution of a stored procedure.
Remark: Only available in SQL Server 2012 and higher.
error_number
is a constant or variable that represents the exception. error_number is int and must be greater than or equal to 50000 and less than or equal to 2147483647.message
is an string or variable that describes the exception. message is nvarchar(2048).state
is a constant or variable between 0 and 255 that indicates the state to associate with the message. state is a tinyint. This post explains why you should/could usestate
.
More information about the
THROW
statement can be found here. Another possible statement to handle exceptions isRAISERROR
but is considered obsolete by Microsoft. More information about theRAISERROR
statement can be found here.
THROW 50000, 'The record does not exist.', 1;
A possible solution of exercise 2 can be found here
We'd like to have 1 stored procedure to insert new OrderDetails
, however make sure that:
- the
Order
andProduct
exist; - the
Order
has not beenShipped
yet; - the
UnitPrice
is rather optional, use it when it's given else retrieve the product's price from theproduct table
; - the
Product
is still instock
, if it's not return0
else1
.
- Create a stored procedure called
SP_Create_OrderDetail
for creating aOrderDetail
. Make sure all the requirements mentioned above are checked.
Make sure the following code can be executed:
-- Version 1
BEGIN TRANSACTION
EXECUTE SP_Create_OrderDetail [OrderId] [ProductId] [UnitPrice] [Quantity];
ROLLBACK
Note that the variables are just placeholders, fill in where necessary.
- Make sure you provide all the necessary parameters (even the optional one);
- Check all the requirements step-by-step if they're not met,
THROW
an exception.
A possible solution of exercise 3 can be found here