PostgreSQL Stored Procedures

Reusable database logic and functions

⚙️ What are Stored Procedures?

Stored procedures are reusable blocks of SQL code saved in the database. They encapsulate business logic, improve performance, and provide a consistent interface for complex operations across your applications.


-- Basic procedure syntax
CREATE PROCEDURE procedure_name(parameters)
LANGUAGE plpgsql
AS $$
BEGIN
    -- SQL statements here
END;
$$;
                                    

Key Procedure Concepts

📦

Functions

Return values to caller

CREATE FUNCTION func() RETURNS type
🔧

Procedures

Execute actions without return

CREATE PROCEDURE proc()
📥

Parameters

IN, OUT, INOUT modes

IN param_name type
🔄

Reusability

Call from anywhere

CALL procedure_name()

🔹 Creating Functions

Functions in PostgreSQL return values and can be used in SELECT statements. They're ideal for calculations, data transformations, and queries that need to return results to the caller.

-- Create sample table
CREATE TABLE employees (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100),
    salary DECIMAL(10,2),
    department VARCHAR(50)
);

INSERT INTO employees (name, salary, department) VALUES
    ('Alice', 75000, 'IT'),
    ('Bob', 65000, 'HR'),
    ('Charlie', 80000, 'IT');

-- Simple function that returns a value
CREATE OR REPLACE FUNCTION get_employee_count()
RETURNS INTEGER
LANGUAGE plpgsql
AS $$
DECLARE
    emp_count INTEGER;
BEGIN
    SELECT COUNT(*) INTO emp_count FROM employees;
    RETURN emp_count;
END;
$$;

-- Call the function
SELECT get_employee_count() AS total_employees;

Result:

total_employees
-----------------
3

🔹 Functions with Parameters

Functions can accept input parameters to make them flexible and reusable. Parameters allow you to pass values into the function and customize its behavior for different scenarios.

-- Function with input parameters
CREATE OR REPLACE FUNCTION calculate_bonus(
    emp_salary DECIMAL,
    bonus_percent DECIMAL
)
RETURNS DECIMAL
LANGUAGE plpgsql
AS $$
BEGIN
    RETURN emp_salary * (bonus_percent / 100);
END;
$$;

-- Use the function
SELECT 
    name,
    salary,
    calculate_bonus(salary, 10) AS bonus
FROM employees;

Result:

name    | salary   | bonus
--------+----------+--------
Alice   | 75000.00 | 7500.00
Bob     | 65000.00 | 6500.00
Charlie | 80000.00 | 8000.00

🔹 Creating Procedures

Procedures perform actions but don't return values directly. They're perfect for data modifications, complex business logic, and operations that need transaction control without returning query results.

-- Create procedure for salary increase
CREATE OR REPLACE PROCEDURE increase_salary(
    dept_name VARCHAR,
    increase_percent DECIMAL
)
LANGUAGE plpgsql
AS $$
BEGIN
    UPDATE employees
    SET salary = salary * (1 + increase_percent / 100)
    WHERE department = dept_name;
    
    RAISE NOTICE 'Salaries increased for % department', dept_name;
END;
$$;

-- Call the procedure
CALL increase_salary('IT', 5);

-- Check results
SELECT name, salary, department 
FROM employees 
WHERE department = 'IT';

Result:

name    | salary   | department
--------+----------+------------
Alice   | 78750.00 | IT
Charlie | 84000.00 | IT

🔹 OUT Parameters

OUT parameters allow procedures to return multiple values without using a RETURN statement. This is useful when you need to return several pieces of information from a single procedure call.

-- Procedure with OUT parameters
CREATE OR REPLACE PROCEDURE get_salary_stats(
    dept_name VARCHAR,
    OUT min_sal DECIMAL,
    OUT max_sal DECIMAL,
    OUT avg_sal DECIMAL
)
LANGUAGE plpgsql
AS $$
BEGIN
    SELECT 
        MIN(salary),
        MAX(salary),
        AVG(salary)
    INTO min_sal, max_sal, avg_sal
    FROM employees
    WHERE department = dept_name;
END;
$$;

-- Call procedure with OUT parameters
CALL get_salary_stats('IT', NULL, NULL, NULL);

Result:

min_sal  | max_sal  | avg_sal
---------+----------+---------
78750.00 | 84000.00 | 81375.00

🔹 Control Structures

PL/pgSQL supports standard programming constructs like IF statements and loops. These control structures enable complex logic, conditional operations, and iterative processing within your stored procedures and functions.

-- Function with IF-ELSE
CREATE OR REPLACE FUNCTION get_salary_grade(emp_salary DECIMAL)
RETURNS VARCHAR
LANGUAGE plpgsql
AS $$
BEGIN
    IF emp_salary >= 80000 THEN
        RETURN 'Senior';
    ELSIF emp_salary >= 70000 THEN
        RETURN 'Mid-Level';
    ELSE
        RETURN 'Junior';
    END IF;
END;
$$;

-- Function with LOOP
CREATE OR REPLACE FUNCTION factorial(n INTEGER)
RETURNS INTEGER
LANGUAGE plpgsql
AS $$
DECLARE
    result INTEGER := 1;
    i INTEGER := 1;
BEGIN
    WHILE i <= n LOOP
        result := result * i;
        i := i + 1;
    END LOOP;
    RETURN result;
END;
$$;

-- Use the functions
SELECT name, salary, get_salary_grade(salary) AS grade
FROM employees;

🔹 Exception Handling

Stored procedures can catch and handle errors gracefully using exception blocks. This prevents errors from crashing your application and allows you to implement custom error handling logic.

-- Function with exception handling
CREATE OR REPLACE FUNCTION safe_divide(
    numerator DECIMAL,
    denominator DECIMAL
)
RETURNS DECIMAL
LANGUAGE plpgsql
AS $$
BEGIN
    RETURN numerator / denominator;
EXCEPTION
    WHEN division_by_zero THEN
        RAISE NOTICE 'Cannot divide by zero';
        RETURN NULL;
    WHEN OTHERS THEN
        RAISE NOTICE 'An error occurred: %', SQLERRM;
        RETURN NULL;
END;
$$;

-- Test the function
SELECT safe_divide(100, 0) AS result;

🔹 Managing Procedures

PostgreSQL provides commands to view, modify, and remove stored procedures and functions. You can also query system catalogs to see all routines and their definitions in your database.

-- View all functions and procedures
SELECT routine_name, routine_type
FROM information_schema.routines
WHERE routine_schema = 'public';

-- Drop function
DROP FUNCTION IF EXISTS get_employee_count();

-- Drop procedure
DROP PROCEDURE IF EXISTS increase_salary(VARCHAR, DECIMAL);

-- Replace existing function
CREATE OR REPLACE FUNCTION get_employee_count()
RETURNS INTEGER
LANGUAGE plpgsql
AS $$
BEGIN
    RETURN (SELECT COUNT(*) FROM employees);
END;
$$;

🔹 Benefits of Stored Procedures

Stored procedures offer significant advantages for database applications. They centralize business logic, improve performance through reduced network traffic, and provide better security through controlled data access.

  • Performance: Reduced network traffic and pre-compiled code
  • Reusability: Write once, use from multiple applications
  • Security: Control data access through procedures
  • Maintainability: Centralized business logic
  • Consistency: Same logic across all applications
  • Transaction Control: Manage complex multi-step operations

🧠 Test Your Knowledge

What is the main difference between a function and a procedure?