Stored procedures are a set of one or more Transact-SQL statements that are compiled and stored on the database server. They can accept input parameters and return multiple values in the form of result sets, output parameters, or return values. Stored procedures offer significant advantages in terms of performance, security, and maintainability for database applications.
This document provides a comprehensive guide to understanding, creating, and utilizing stored procedures in Microsoft SQL Server.
You can create a stored procedure using the CREATE PROCEDURE
or CREATE PROC
statement.
The basic syntax is as follows:
CREATE PROCEDURE procedure_name
[ @parameter1 datatype [ = default_value ] [ OUTPUT ]
, @parameter2 datatype [ = default_value ] [ OUTPUT ]
, ... ]
AS
BEGIN
-- Transact-SQL statements
SELECT column1, column2
FROM your_table
WHERE some_column = @parameter1;
-- Other operations like INSERT, UPDATE, DELETE can also be included
END
GO
Key components:
CREATE PROCEDURE
: Keyword to start the procedure definition.procedure_name
: A unique name for your stored procedure.@parameter_name
: Optional parameters, prefixed with '@'.datatype
: The data type of the parameter (e.g., INT
, VARCHAR(50)
, DATETIME
).= default_value
: An optional default value for the parameter if none is provided during execution.OUTPUT
: Indicates that the parameter is an output parameter, returning a value back to the caller.AS
: Separates the procedure signature from the body.BEGIN...END
: Encloses the Transact-SQL statements that form the procedure's logic.GO
: A batch separator, not part of the T-SQL itself.
Stored procedures are executed using the EXECUTE
or EXEC
command.
EXECUTE procedure_name [ @parameter1 = value1, @parameter2 = value2, ... ];
-- or
EXEC procedure_name value1, value2, ...; -- If parameters are in the defined order
You can also execute a procedure and capture its return value or output parameters.
Stored procedures can use various types of parameters to make them flexible and reusable.
These parameters pass values into the stored procedure. They are the most common type.
CREATE PROCEDURE GetCustomerById
@CustomerID INT
AS
BEGIN
SELECT *
FROM Customers
WHERE CustomerID = @CustomerID;
END
GO
EXEC GetCustomerById @CustomerID = 10;
These parameters are used to return a single value from the stored procedure back to the caller. The OUTPUT
keyword is crucial.
CREATE PROCEDURE GetCustomerCountByCity
@CityName VARCHAR(50),
@CustomerCount INT OUTPUT
AS
BEGIN
SELECT @CustomerCount = COUNT(*)
FROM Customers
WHERE City = @CityName;
END
GO
DECLARE @Count INT;
EXEC GetCustomerCountByCity @CityName = 'London', @CustomerCount = @Count OUTPUT;
SELECT @Count AS NumberOfCustomersInLondon;
Stored procedures can also return an integer status code using the RETURN
statement. This is typically used to indicate success or failure, or specific status conditions.
CREATE PROCEDURE AddProduct
@ProductName VARCHAR(100),
@Price DECIMAL(10, 2)
AS
BEGIN
IF EXISTS (SELECT * FROM Products WHERE ProductName = @ProductName)
BEGIN
RETURN 1; -- Error: Product already exists
END
ELSE
BEGIN
INSERT INTO Products (ProductName, Price) VALUES (@ProductName, @Price);
RETURN 0; -- Success
END
END
GO
DECLARE @Result INT;
EXEC @Result = AddProduct @ProductName = 'Gadget', @Price = 29.99;
IF @Result = 0
PRINT 'Product added successfully.';
ELSE
PRINT 'Product already exists.';
EXECUTE
command.TRY...CATCH
blocks for robust error handling.SET NOCOUNT ON
: This prevents the "x rows affected" messages from being returned, which can improve performance and reduce network traffic, especially when called from applications.
CREATE PROCEDURE GetOrderDetails
@OrderID INT
AS
BEGIN
SET NOCOUNT ON; -- Suppress row count messages
BEGIN TRY
SELECT
od.ProductID,
p.ProductName,
od.Quantity,
od.UnitPrice
FROM OrderDetails AS od
JOIN Products AS p ON od.ProductID = p.ProductID
WHERE od.OrderID = @OrderID;
IF @@ROWCOUNT = 0
BEGIN
-- Handle case where OrderID doesn't exist or has no details
PRINT 'No details found for the specified OrderID.';
RETURN -1; -- Custom return code for 'not found'
END
RETURN 0; -- Success
END TRY
BEGIN CATCH
-- Log the error or handle it as appropriate
PRINT 'An error occurred while retrieving order details.';
-- Consider using THROW or RAISERROR for more detailed error reporting
RETURN -2; -- Custom return code for 'error'
END CATCH
END
GO
CREATE PROCEDURE GetAllProducts
AS
BEGIN
SET NOCOUNT ON;
SELECT ProductID, ProductName, UnitPrice
FROM Products
ORDER BY ProductName;
END
GO
EXEC GetAllProducts;
CREATE PROCEDURE AddNewCustomer
@FirstName VARCHAR(50),
@LastName VARCHAR(50),
@Email VARCHAR(100)
AS
BEGIN
SET NOCOUNT ON;
IF EXISTS (SELECT * FROM Customers WHERE Email = @Email)
BEGIN
RAISERROR('Customer with this email already exists.', 16, 1);
RETURN 1;
END
ELSE
BEGIN
INSERT INTO Customers (FirstName, LastName, Email, CreatedDate)
VALUES (@FirstName, @LastName, @Email, GETDATE());
PRINT 'Customer added successfully.';
RETURN 0;
END
END
GO
EXEC AddNewCustomer @FirstName = 'Jane', @LastName = 'Doe', @Email = 'jane.doe@example.com';