Back

    Advanced Stored Procedures, Functions & Triggers

    Write production-grade procedures with error handling, audit triggers, and dynamic SQL.

    ๐ŸŽฏ What You'll Learn

    • Procedures with error handling, locking, and transaction control
    • Table-returning functions for reusable report logic
    • Audit triggers that automatically log every data change
    • Validation triggers to enforce business rules at the database level
    • Dynamic SQL with injection-safe patterns

    ๐Ÿฆ Production-Grade Procedures

    Think of a stored procedure like a bank teller's checklist โ€” validate the request, lock the accounts, perform the transfer, log it, and handle anything that goes wrong. This example shows a fund transfer with full error handling and row locking.

    Fund Transfer Procedure

    Complete procedure with validation, locking, and error handling

    Try it Yourself ยป
    SQL
    -- Advanced stored procedure with error handling
    -- PostgreSQL PL/pgSQL
    
    CREATE OR REPLACE FUNCTION transfer_funds(
        p_from_account INT,
        p_to_account INT,
        p_amount DECIMAL(15,2)
    )
    RETURNS TEXT
    LANGUAGE plpgsql
    AS $$
    DECLARE
        v_from_balance DECIMAL(15,2);
        v_from_name VARCHAR(100);
        v_to_name VARCHAR(100);
    BEGIN
        -- Validate amount
        IF p_amount <= 0 THEN
            RAISE EXCEPTION 'Transfer amount must be positive: %', p_amount;
        END IF;
    
        -- Lock rows to prevent race
    ...

    ๐Ÿ“Š Table-Returning Functions

    Functions that return tables can be used in FROM clauses just like real tables. They're perfect for encapsulating complex report logic that's reused across the application.

    ๐Ÿ’ก Pro Tip โ€” Functions vs Procedures

    Use functions when you need to return data (can be used in SELECT/FROM). Use procedures when you need to perform actions with transaction control (COMMIT/ROLLBACK inside the routine).

    Table-Returning Function

    Create reusable report functions with optional parameters

    Try it Yourself ยป
    SQL
    -- Table-returning function (set-returning function)
    CREATE OR REPLACE FUNCTION get_employee_report(
        p_department VARCHAR DEFAULT NULL,
        p_min_salary DECIMAL DEFAULT 0
    )
    RETURNS TABLE (
        employee_name VARCHAR,
        department VARCHAR,
        salary DECIMAL,
        hire_date DATE,
        years_employed INT,
        salary_rank INT
    )
    LANGUAGE plpgsql
    AS $$
    BEGIN
        RETURN QUERY
        SELECT
            e.name,
            d.department_name,
            e.salary,
            e.hire_date,
            EXTRACT(YEAR FROM AGE(C
    ...

    ๐Ÿ“ Audit Triggers

    An audit trigger automatically records who changed what, when, and what the old/new values were. One generic function can audit every table in your database.

    Generic Audit Trigger

    Automatically log INSERT, UPDATE, and DELETE on any table

    Try it Yourself ยป
    SQL
    -- Audit trigger: automatically log all changes
    CREATE TABLE audit_log (
        id SERIAL PRIMARY KEY,
        table_name VARCHAR(100),
        operation VARCHAR(10),
        old_data JSONB,
        new_data JSONB,
        changed_by VARCHAR(100) DEFAULT current_user,
        changed_at TIMESTAMP DEFAULT NOW()
    );
    
    -- Generic audit trigger function
    CREATE OR REPLACE FUNCTION fn_audit_trigger()
    RETURNS TRIGGER
    LANGUAGE plpgsql
    AS $$
    BEGIN
        IF TG_OP = 'INSERT' THEN
            INSERT INTO audit_log (table_name, operation, new
    ...

    โœ… Validation Triggers

    BEFORE triggers can validate and modify data before it's written. They enforce business rules that application code might miss โ€” like a bouncer checking IDs at the door.

    โš ๏ธ Common Mistake

    Forgetting to RETURN NEW in a BEFORE trigger. If you don't return the row, the INSERT/UPDATE is silently cancelled. AFTER triggers return value is ignored.

    Validation Trigger

    Enforce business rules before data is written

    Try it Yourself ยป
    SQL
    -- Validation trigger: enforce business rules
    CREATE OR REPLACE FUNCTION fn_validate_order()
    RETURNS TRIGGER
    LANGUAGE plpgsql
    AS $$
    BEGIN
        -- Rule 1: Order total must be positive
        IF NEW.total <= 0 THEN
            RAISE EXCEPTION 'Order total must be positive, got: %', NEW.total;
        END IF;
    
        -- Rule 2: Cannot backdate orders more than 7 days
        IF NEW.order_date < CURRENT_DATE - INTERVAL '7 days' THEN
            RAISE EXCEPTION 'Cannot backdate order beyond 7 days';
        END IF;
    
        -- Rul
    ...

    ๐Ÿ”ง Dynamic SQL

    Dynamic SQL builds queries as strings at runtime. Powerful but dangerous โ€” always validate inputs and use format(%I) for identifiers and parameterised queries for values to prevent SQL injection.

    Safe Dynamic SQL

    Build flexible queries with injection protection

    Try it Yourself ยป
    SQL
    -- Dynamic SQL for flexible queries
    CREATE OR REPLACE FUNCTION search_table(
        p_table_name TEXT,
        p_column TEXT,
        p_search_value TEXT,
        p_limit INT DEFAULT 100
    )
    RETURNS JSONB
    LANGUAGE plpgsql
    AS $$
    DECLARE
        v_query TEXT;
        v_result JSONB;
    BEGIN
        -- Validate table exists (prevent SQL injection!)
        IF NOT EXISTS (
            SELECT 1 FROM information_schema.tables
            WHERE table_schema = 'public'
              AND table_name = p_table_name
        ) THEN
            RAISE EXCEPTION 'T
    ...

    ๐Ÿ“‹ Quick Reference

    FeatureWhen to Use
    FUNCTIONReturn data, usable in SELECT/FROM
    PROCEDUREActions with transaction control
    BEFORE triggerValidate/modify data before write
    AFTER triggerAudit logging, notifications
    format(%I)Safe dynamic identifier injection

    ๐ŸŽ‰ Lesson Complete!

    You can now write production-grade stored procedures, audit triggers, and dynamic SQL. Next, dive into advanced transaction isolation levels!

    Sign up for free to track which lessons you've completed and get learning reminders.

    Previous

    Cookie & Privacy Settings

    We use cookies to improve your experience, analyze traffic, and show personalized ads. You can manage your preferences below.

    By clicking "Accept All", you consent to our use of cookies for analytics and personalized advertising. You can customize your preferences or reject non-essential cookies.

    Privacy Policy โ€ข Terms of Service