Stored Procedures
Variables
Variables are used to hold values.
Before we use variables, we must declare them:
DECLARE
@VariableName datatype
, @VariableName datatype
, @VariableName datatype
...
We can assign values by hardcoding them:
DECLARE @FirstName varchar(40)
SET @FirstName = 'Dana'
-- assigning a single variable from a literal is the only time I can use SET, otherwise I use SELECT
We can hardcode many at a time:
DECLARE @FirstName varchar(40)
, @LastName varchar(40)
SELECT @FirstName = 'Dana'
, @LastName = 'Marsh'
We can assign values from a query:
DECLARE @FirstName varchar(40)
SELECT @FirstName = StaffFirstName
FROM Staff
WHERE StaffID = 1
Or from a query that returns multiple columns/expressions:
DECLARE @FirstName varchar(40)
, @LastName varchar(40)
SELECT @FirstName = StaffFirstName
, @LastName = StaffLastName
FROM Staff
WHERE StaffID = 1
Flow Control
We can control the flow of SQL (AKA choose your own adventure) by using an IF-ELSE
structure. The general syntax looks as follows:
IF condition
BEGIN
statements -- these statements only execute if the condition is TRUE
END
ELSE
BEGIN
statements -- these statements only execute if the condition is FALSE
END
For example:
DECLARE @Total int
, @Result varchar(10)
SET @Total = 100
IF @Total = 100
BEGIN
SET @Result = 'IS'
END
ELSE
BEGIN
SET @Result = 'IS NOT'
END
PRINT 'The total ' + @Result + ' 100.' -- PRINT is not how we should return messages to the user: it's primarily used for testing/debugging.
Another example using EXISTS
:
IF EXISTS (SELECT * FROM Staff WHERE StaffID = 5)
BEGIN
SELECT 'There is a record for that StaffID'
END
ELSE
BEGIN
SELECT 'There is NOT a record for that StaffID'
END
Batches & GO
A batch is a series of SQL statements.
GO
is a batch terminator. It causes the batch to GO
to the server for execution.
It is recommended to use GO
between batches to ensure they work properly: for example, if we’re changing a CONSTRAINT
and then running a related INSERT
, I want to make sure my CONSTRAINT
is in place before INSERT
ing, so I’ll put them in separate batches.
Stored Procedures
A stored procedure is a set of SQL statements.
Syntax
- To create a new stored procedure:
CREATE PROCEDURE ProcedureName AS -- SQL statements go here RETURN
- To drop an existing stored procedure:
DROP PROCEDURE ProcedureName
- To change an existing stored procedure by replacing its definition:
ALTER PROCEDURE ProcedureName -- SQL statements go here RETURN
- To run a stored procedure:
EXEC ProcedureName
If the procedure has parameters, they are listed after, separated by commas:
EXEC ProcedureName Param1, Param2
- To display the definition of an existing stored procedure:
EXEC sp_helptext ProcedureName
Parameters
We can pass in parameters to be used within our stored procedures. Think of parameters as inputs into the SP, or info that is needed for the SP to run properly.
In this case, in order to look up a student, I need their StudentID
, so it is a parameter:
CREATE PROCEDURE LookupStudent (@StudentID int)
AS
-- SQL statements go here
RETURN
We can (and SHOULD) also initalize the values of the parameters. This gives us more control over what to do if those parameters aren’t provided when the SP is run.
CREATE PROCEDURE LookupStudent (@StudentID int = NULL)
AS
-- SQL statements go here
RETURN
Raising errors
To raise an error within our stored procedure, we use RAISERROR
:
RAISERROR(msg_text, severity, state)
For example:
RAISERROR('Must provide required parameters', 16, 1)
Scenarios where we will want to raise an error include:
- Required parameters are not passed to a stored procedure.
- A DML operation failed (
INSERT
,UPDATE
,DELETE
). - An
UPDATE
/DELETE
operation affected 0 rows (this may not always require an error, but if not specified, confirm with your instructor/client/boss).
Global variables
@@error
returns the error count for the last statement executed. If the last statement did not error, it has a value of0
.ℹ️ We will check this after every DML operation.
@@identity
returns the last-inserted identity value.@@rowcount
returns the number of rows affected by the last statement executed.
Transactions
Transactions are SQL structures that ensure that a complete Logical Unit of Work is complete.
🔥 Transactions are needed in any Stored Procedure that has more than 1 DML statement occurring.
BEGIN TRANSACTION
marks the beginning of the transactionCOMMIT TRANSACTION
marks the end of the transaction, and makes the changes permanent.ROLLBACK TRANSACTION
marks the end of the transaction, and “undoes” the changes: we go back to the state we were in when the transaction began.
Putting it all together…
Let’s say we are creating an SP to register a student. Our stored procedure would:
- Check to see if parameters are null. If so,
RAISERROR
. - Otherwise:
BEGIN TRANSACTION
INSERT
into Grade- Check if the
INSERT
failed. If so,RAISERROR
&ROLLBACK
. - Otherwise:
UPDATE
Student.BalanceOwing- Check if the
UPDATE
failed. If so,RAISERROR
&ROLLBACK
. - Otherwise,
COMMIT
.