CREATE FUNCTION lets you define reusable user-defined functions (UDFs) in SQL or PL/pgSQL, extending PostgreSQL with custom logic.
A user-defined function (UDF) is an SQL or PL/pgSQL block you store in the database and call like any built-in function. UDFs encapsulate business logic, reduce duplication, and speed up complex calculations.
Create a UDF when you need parameters, conditional logic, loops, or the ability to return scalars, rows, or sets on demand. Views are static SELECTs and cannot accept parameters.
Use CREATE FUNCTION, declare parameters and the return type, then wrap a single SQL statement in $$
delimiters using LANGUAGE sql.
This SQL UDF returns the lifetime spend of one customer from the Orders table.
CREATE OR REPLACE FUNCTION total_spent(customer_id INT)
RETURNS NUMERIC(12,2) AS $$
SELECT COALESCE(SUM(total_amount),0)
FROM Orders
WHERE customer_id = $1;
$$ LANGUAGE sql IMMUTABLE;
Choose LANGUAGE plpgsql. You can declare variables, use IF, loops, and raise notices. Useful for multi-step procedures.
CREATE OR REPLACE FUNCTION restock_product(p_id INT, add_qty INT)
RETURNS VOID AS $$
BEGIN
UPDATE Products SET stock = stock + add_qty WHERE id = p_id;
INSERT INTO InventoryLog(product_id, qty_added, logged_at)
VALUES (p_id, add_qty, NOW());
END;
$$ LANGUAGE plpgsql;
Invoke it in any SELECT, INSERT, UPDATE, or as a standalone statement: SELECT total_spent(42);
Mark functions IMMUTABLE or STABLE when possible for planner optimizations. Add STRICT to auto-return NULL on any NULL parameter. Version functions with OR REPLACE to avoid drop/recreate downtime.
Use CREATE OR REPLACE FUNCTION
to update logic. Add RAISE NOTICE
statements in PL/pgSQL for logging. pgAdmin
and psql -E
help inspect compiled source.
Yes, declare RETURNS TABLE(col1 type, ...)
or RETURNS SETOF
. Query it like a regular table: SELECT * FROM top_customers();
Add IF EXISTS to avoid an error, or use CREATE OR REPLACE so callers stay intact.
PostgreSQL supports PL/Python, PL/Perl, PL/V8, and more after installing extensions.
SQL UDFs are inlined by the planner when possible. Marking functions IMMUTABLE and STRICT helps the optimizer. PL/pgSQL incurs minimal overhead for most workloads.