User-Defined Functions
A user-defined function (UDF) is a custom function, written by a database developer, that behaves like a built-in function such as UPPER() or ROUND() — it can be called directly inside a SELECT list, a WHERE clause, or anywhere else an expression is expected. Where a stored procedure is invoked as its own standalone statement with CALL, a function is invoked inline, as part of a larger query.
Scalar functions vs table-valued functions
Type | Returns | Used like |
|---|---|---|
Scalar function | A single value (a number, string, date, etc.) | A built-in function inside SELECT, WHERE, or ORDER BY |
Table-valued function | A full result set (a set of rows and columns) | A table or view inside a FROM clause |
Worked example: a scalar function
Suppose a discount needs to be applied to a price wherever it appears across many queries. Rather than repeating the same arithmetic expression everywhere, wrap it in a function:
PostgreSQL: a scalar function
CREATE FUNCTION discounted_price(p_price NUMERIC, p_discount_pct NUMERIC) RETURNS NUMERIC LANGUAGE plpgsql AS $$ BEGIN RETURN ROUND(p_price * (1 - p_discount_pct / 100), 2); END; $$; -- Used directly inside a SELECT, just like a built-in function SELECT product_name, price, discounted_price(price, 15) AS sale_price FROM products;
The function can also be used in a WHERE clause, exactly like any other expression:
Using the function to filter rows
SELECT product_name FROM products WHERE discounted_price(price, 15) < 50;
Worked example: a table-valued function
A table-valued function returns a whole result set and can be queried like a table. This is useful for encapsulating a parameterized query that is reused with different inputs:
PostgreSQL: a table-valued function
CREATE FUNCTION orders_above(p_amount NUMERIC) RETURNS TABLE (order_id INT, customer_id INT, order_total NUMERIC) LANGUAGE sql AS $$ SELECT order_id, customer_id, order_total FROM orders WHERE order_total > p_amount; $$; -- Queried like a table SELECT * FROM orders_above(500) ORDER BY order_total DESC;
Functions vs procedures
A function returns a value (scalar or table) and can be embedded inside a query expression.
A procedure is invoked as its own statement and does not have to return a value; it is meant for a sequence of actions.
A function generally should not modify data as a side effect, since it may be called anywhere in a query, potentially multiple times per row — a procedure is the appropriate place for INSERT/UPDATE/DELETE logic.
A user-defined function extends SQL with custom, reusable logic callable like a built-in function.
Scalar functions return a single value; table-valued functions return a queryable result set.
Functions are used inline within a query expression, unlike procedures, which are called as standalone statements.
Dialect syntax and rules (especially around side effects) vary significantly, so check documentation for the target database.