I’ll walk you through the process of creating and enhancing a SQL Server stored procedure to analyze shipping data. We’ll start with a basic implementation, identify its limitations, and iteratively improve it to make it more robust, flexible, and user-friendly. By the end, you’ll have a practical, production-ready stored procedure that demonstrates best practices in SQL development.
Analyzing Shipping Data
Imagine you’re working with an e-commerce database that tracks customer orders. One common task is to retrieve all orders shipped on a specific date. While this seems simple, there are several challenges to address:
- Input Validation: What if the user forgets to provide a shipping date?
- Error Handling: How do we inform the user of errors in a clear and actionable way?
- Flexibility: Can we allow users to sort results in ascending or descending order?
- User Experience: How do we handle cases where no orders match the criteria?
Let’s tackle these challenges step by step.
The Basic Stored Procedure
We’ll start with a simple stored procedure that retrieves orders shipped on a specific date. Here’s the initial implementation:
CREATE PROCEDURE shipping_date_sp @shippedDate DATE AS BEGIN -- Check if the input parameter is NULL IF @shippedDate IS NULL BEGIN PRINT 'Please enter a valid ship date'; RETURN; -- Exit the procedure if no valid input is provided END -- Proceed with the query if the input parameter is valid SELECT o.OrderID, c.CompanyName, c.Phone, CONVERT(VARCHAR(20), o.OrderDate, 107) AS OrderDate, CONVERT(VARCHAR(20), o.RequiredDate, 107) AS RequiredDate, CONVERT(VARCHAR(20), o.ShippedDate, 107) AS ShippedDate FROM Orders AS o JOIN Customers AS c ON c.CustomerID = o.CustomerID WHERE o.ShippedDate = @shippedDate ORDER BY o.OrderDate; END
Explanation
- Parameter Check: The procedure checks if
@shippedDate
isNULL
. If it is, it prints an error message and exits usingRETURN
. - Query Execution: If the input is valid, it retrieves orders shipped on the specified date, joining the
Orders
andCustomers
tables. - Date Formatting: The
CONVERT
function formats dates into a readable format (e.g.,Mar 12, 2024
).
Limitations
- No feedback if no orders match the criteria.
- No flexibility in sorting results.
- Limited error handling (uses
PRINT
, which is less visible).
Enhancing the Stored Procedure
Let’s address the limitations by adding the following features:
- Default Parameter Value: Allow the procedure to be called without a parameter.
- Improved Error Handling: Use
RAISERROR
for better visibility. - Sort Order Flexibility: Allow users to specify ascending or descending order.
- Additional Data Points: Include the customer’s country and calculate the number of days it took to ship the order.
- No Results Feedback: Inform the user if no orders match the criteria.
Here’s the enhanced version:
CREATE PROCEDURE shipping_date_sp @shippedDate DATE = NULL, @sortOrder NVARCHAR(4) = 'ASC' AS BEGIN -- Validate required parameter IF @shippedDate IS NULL BEGIN RAISERROR('Error: @shippedDate parameter is required. Please provide a shipping date.', 16, 1); RETURN; END -- Validate sort order IF UPPER(@sortOrder) NOT IN ('ASC', 'DESC') BEGIN RAISERROR('Invalid sort order. Use ''ASC'' (ascending) or ''DESC'' (descending).', 16, 1); RETURN; END -- Dynamic SQL for safe query construction DECLARE @sql NVARCHAR(MAX); SET @sql = N' SELECT o.OrderID, c.CompanyName, c.Phone, c.Country, CONVERT(VARCHAR(20), o.OrderDate, 107) AS OrderDate, CONVERT(VARCHAR(20), o.RequiredDate, 107) AS RequiredDate, CONVERT(VARCHAR(20), o.ShippedDate, 107) AS ShippedDate, DATEDIFF(DAY, o.OrderDate, o.ShippedDate) AS DaysToShip FROM Orders AS o JOIN Customers AS c ON c.CustomerID = o.CustomerID WHERE o.ShippedDate = @inputDate ORDER BY o.OrderDate ' + @sortOrder + ';'; -- Execute dynamic SQL with parameter EXEC sp_executesql @sql, N'@inputDate DATE', @inputDate = @shippedDate; -- Provide feedback if no results IF @@ROWCOUNT = 0 BEGIN PRINT 'No orders found shipped on: ' + CONVERT(VARCHAR, @shippedDate, 107); END END
Key Enhancements
- Default Parameter Value:
@shippedDate
defaults toNULL
, allowing the procedure to be called without parameters. - Improved Error Handling:
RAISERROR
provides more visible and actionable error messages. - Sort Order Flexibility: Users can specify
ASC
orDESC
for sorting. - Additional Data Points: The query now includes
Country
and calculatesDaysToShip
. - No Results Feedback: A message is printed if no orders match the criteria.
Testing the Procedure
Let’s test the procedure with different scenarios:
Valid Input
EXEC shipping_date_sp @shippedDate = '2023-10-01', @sortOrder = 'DESC';
- Retrieves orders shipped on October 1, 2023, sorted in descending order.
Missing Parameter
EXEC shipping_date_sp;
- Output:
Error: @shippedDate parameter is required. Please provide a shipping date.
Invalid Sort Order
EXEC shipping_date_sp @shippedDate = '2023-10-01', @sortOrder = 'RANDOM';
- Output:
Invalid sort order. Use 'ASC' (ascending) or 'DESC' (descending).
No Results
EXEC shipping_date_sp @shippedDate = '2099-01-01';
- Output:
No orders found shipped on: Jan 01, 2099
Final Thoughts
This enhanced stored procedure demonstrates how to build robust, user-friendly database solutions. By incorporating input validation, dynamic SQL, and clear error messaging, we’ve created a tool that is both flexible and reliable.