πŸŽ‰ 75% of content is free forever β€” Unlock Premium from $10/mo β†’
CW
Search courses…
πŸ’Ό Servicesℹ️ Aboutβœ‰οΈ ContactView Pricing Plansfrom $10

Stored Procedures

SQL AdvancedProcedures🟒 Free Lesson

Advertisement

SQL Advanced

Stored Procedures

Encapsulate business logic into reusable, precompiled SQL routines stored directly in the database.

  • Reusability β€” Write once, call from anywhere without duplicating SQL code
  • Security β€” Grant execution permissions without exposing underlying table access
  • Performance β€” Precompiled execution plans reduce parsing overhead on repeated calls Stored procedures are the backbone of enterprise database applications.

What Is a Stored Procedure?

DfStored Procedure

A named collection of SQL statements stored in the database that can be executed (called) by name. Procedures can accept input parameters, return output parameters, and include control-flow logic such as IF/ELSE and WHILE loops.

Once created, a stored procedure's SQL is parsed and its execution plan is cached by the database engine. Subsequent calls reuse the cached plan, avoiding re-parsing and re-optimization β€” a significant performance benefit for complex queries.

-- Create a simple stored procedure
CREATE PROCEDURE GetActiveCustomers
AS
BEGIN
    SELECT customer_id, name, email, phone
    FROM customers
    WHERE status = 'ACTIVE'
    ORDER BY name;
END;

-- Execute the procedure
EXEC GetActiveCustomers;

Creating Procedures with Parameters

DfInput Parameter

A value passed into a stored procedure when it is called. Parameters allow procedures to be flexible and reusable with different data.

DfOutput Parameter

A parameter that returns a value from the procedure back to the caller. Declared with the OUTPUT keyword.

-- Procedure with input and output parameters
CREATE PROCEDURE GetCustomerOrderSummary
    @customer_id INT,
    @total_orders INT OUTPUT,
    @total_spent DECIMAL(10,2) OUTPUT
AS
BEGIN
    SELECT
        @total_orders = COUNT(*),
        @total_spent = ISNULL(SUM(total), 0)
    FROM orders
    WHERE customer_id = @customer_id;
END;

-- Call with output parameters
DECLARE @orders INT, @spent DECIMAL(10,2);
EXEC GetCustomerOrderSummary
    @customer_id = 42,
    @total_orders = @orders OUTPUT,
    @total_spent = @spent OUTPUT;

SELECT @orders AS TotalOrders, @spent AS TotalSpent;

Default Parameter Values

Parameters can have default values, making them optional when calling the procedure.

CREATE PROCEDURE SearchProducts
    @category NVARCHAR(50) = NULL,
    @min_price DECIMAL(10,2) = 0,
    @max_price DECIMAL(10,2) = 999999,
    @sort_by NVARCHAR(20) = 'name'
AS
BEGIN
    SELECT product_id, name, category, price
    FROM products
    WHERE (@category IS NULL OR category = @category)
      AND price BETWEEN @min_price AND @max_price
    ORDER BY
        CASE @sort_by
            WHEN 'name' THEN name
            WHEN 'price' THEN CAST(price AS NVARCHAR)
        END;
END;

-- Call with various parameter combinations
EXEC SearchProducts;                          -- all products
EXEC SearchProducts @category = 'Electronics'; -- electronics only
EXEC SearchProducts @min_price = 50, @max_price = 200;
EXEC SearchProducts @category = 'Books', @sort_by = 'price';

Control Flow in Procedures

Procedures support conditional logic and loops for complex business rules.

CREATE PROCEDURE ProcessOrder
    @order_id INT
AS
BEGIN
    DECLARE @status NVARCHAR(20);
    DECLARE @total DECIMAL(10,2);

    SELECT @status = status, @total = total
    FROM orders WHERE order_id = @order_id;

    IF @status = 'CANCELLED'
    BEGIN
        PRINT 'Order is already cancelled.';
        RETURN;
    END

    IF @total > 1000
    BEGIN
        UPDATE orders
        SET status = 'PENDING_APPROVAL',
            discount = @total * 0.10
        WHERE order_id = @order_id;

        INSERT INTO approval_queue (order_id, requested_by, request_date)
        VALUES (@order_id, SYSTEM_USER, GETDATE());
    END
    ELSE
    BEGIN
        UPDATE orders
        SET status = 'CONFIRMED'
        WHERE order_id = @order_id;

        INSERT INTO order_log (order_id, action, action_date)
        VALUES (@order_id, 'AUTO_CONFIRMED', GETDATE());
    END
END;

Modifying and Dropping Procedures

-- Alter an existing procedure
ALTER PROCEDURE GetActiveCustomers
    @min_order_count INT = 0
AS
BEGIN
    SELECT c.customer_id, c.name, c.email,
           COUNT(o.order_id) AS order_count
    FROM customers c
    LEFT JOIN orders o ON c.customer_id = o.customer_id
    WHERE c.status = 'ACTIVE'
    GROUP BY c.customer_id, c.name, c.email
    HAVING COUNT(o.order_id) >= @min_order_count
    ORDER BY order_count DESC;
END;

-- Drop a procedure
DROP PROCEDURE IF EXISTS GetActiveCustomers;

-- Check if a procedure exists
IF OBJECT_ID('GetActiveCustomers', 'P') IS NOT NULL
    PRINT 'Procedure exists';
ELSE
    PRINT 'Procedure does not exist';

Error Handling in Procedures

Always include error handling in stored procedures. Unhandled errors leave transactions in an indeterminate state and can cause data inconsistency.

CREATE PROCEDURE TransferFunds
    @from_account INT,
    @to_account INT,
    @amount DECIMAL(10,2)
AS
BEGIN
    SET NOCOUNT ON;

    BEGIN TRY
        BEGIN TRANSACTION;

        -- Validate sufficient balance
        DECLARE @balance DECIMAL(10,2);
        SELECT @balance = balance FROM accounts WHERE id = @from_account;

        IF @balance < @amount
        BEGIN
            RAISERROR('Insufficient funds. Available: %.2f', 16, 1, @balance);
            RETURN;
        END

        UPDATE accounts SET balance = balance - @amount WHERE id = @from_account;
        UPDATE accounts SET balance = balance + @amount WHERE id = @to_account;

        INSERT INTO transfers (from_id, to_id, amount, transfer_date)
        VALUES (@from_account, @to_account, @amount, GETDATE());

        COMMIT;
        PRINT 'Transfer completed successfully.';
    END TRY
    BEGIN CATCH
        IF @@TRANCOUNT > 0
            ROLLBACK;

        DECLARE @msg NVARCHAR(4000) = ERROR_MESSAGE();
        DECLARE @sev INT = ERROR_SEVERITY();
        RAISERROR(@msg, @sev, 1);
    END CATCH
END;

Advantages Over Inline SQL

FeatureStored ProcedureInline SQL
PerformancePrecompiled execution planParsed on every execution
SecurityGranular EXECUTE permissionsRequires direct table access
Network TrafficSingle call to executeFull SQL text sent each time
MaintainabilityCentralized, version-controlled logicScattered across application code
ReusabilityCall from multiple applicationsDuplicated across clients
SQL InjectionParameters are safe by designRequires careful escaping

Key Takeaways

  1. Stored procedures encapsulate SQL logic into reusable, named routines stored in the database
  2. Parameters (input and output) make procedures flexible and adaptable to different scenarios
  3. Precompiled execution plans provide performance benefits for frequently called operations
  4. Always use TRY/CATCH for error handling to maintain transaction integrity
  5. Grant EXECUTE permissions on procedures instead of direct table access for better security
  6. Use SET NOCOUNT ON to suppress row count messages and improve performance
⭐

Premium Content

Stored Procedures

Unlock this lesson and 900+ advanced tutorials with a Premium plan.

🎯End-to-end Projects
πŸ’ΌInterview Prep
πŸ“œCertificates
🀝Community Access

Already a member? Log in

Need Expert SQL Help?

Get personalized tutoring, project support, or professional consulting.

Advertisement