PostgreSQL functions
PostgreSQL has a lot of built-in functions, such as Trigonometric Functions, String Functions, IP address functions, etc. But we’re not limited by built-in functions. PostgreSQL (as well as other RDBMS) allows creating custom functions. In this tutorial we will take a look at user-defined functions.
PostgreSQL supports the following programming languages for writing functions:
- SQL
- PL/pgSQL
- C
- PL/Python
- PL/Tcl
- some other languages
Create functions with PL/pgSQL
Functions written in PL/pgSQL can contain a variable declaration, conditional and looping constructions, exception handling and so on. PL/pgSQL is a block-structured and case-insensitive language.
Base syntax for creating functions in PostgreSQL looks into the following way:
CREATE
OR REPLACE FUNCTION function_name (arguments)
RETURNS r_type AS $$
DECLARE
declarations
BEGIN
statements
END;
$$
LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION
- creates a new function named by function_name
in case when such function doesn’t exists,
otherwise replaces the existing function.
arguments
- is a list of function’s arguments. Functions can have zero or more parameters(arguments). We may specify only
parameter type, e.g. (int4, varchar(40))
. In that case within a function body, the parameters of the function are referred to
as $1, $2,..
and so on, in the order they are defined. But we also can specify parameters names together with its
types (price int4, name varchar(40))
.
RETURNS
- returned data type from the function. In our case r_type
is specified type which will be returned from the
function.
DECLARE declarations;
- is a declaration section, which contains the variables names and its data types.
BEGIN Statement;
- is a statement section which is the main body of the function. It may contain unlimited nested sub-blocks (
with DECLARE, BEGIN, END sections).
END
- finishes the statement block.
BEGIN/END
sections doesn’t start or stop transactions. It’s used for grouping blocks of code.
Function example
Let’s assume we have a table vehicle
which has the following columns:
vehicle_id - vehicle's ID
make - vehicle's make
model - vehicle's model
price - vehicle's price in $
Now let’s create a function which accepts desired price as a parameter and prints the amount of vehicles with price lower than or equals to desired price:
CREATE
OR REPLACE FUNCTION getCheapVehicleCount(desiredPrice INTEGER)
RETURNS INTEGER AS $$
DECLARE
total INTEGER;
BEGIN
SELECT count(*)
INTO total
FROM vehicle v
WHERE v.price <= desiredPrice;
RETURN total;
END;
$$
LANGUAGE plpgsql;
Now let’s create a simple table vehicle
:
DROP TABLE IF EXISTS vehicle;
CREATE TABLE vehicle
(
vehicle_id SERIAL NOT NULL,
make VARCHAR(100) NOT NULL,
model VARCHAR(100) NOT NULL,
price NUMERIC(5) NOT NULL
);
and fill in it with the test data:
INSERT INTO vehicle (make, model, price)
VALUES ('Toyota', 'Camry', 25560);
INSERT INTO vehicle (make, model, price)
VALUES ('Audi', 'A4', 42825);
INSERT INTO vehicle (make, model, price)
VALUES ('Acura', 'ILX', 30840);
INSERT INTO vehicle (make, model, price)
VALUES ('BMW', '5 Series ', 67470);
Verifying function
For verification let’s find how many vehicles have price less or equals to 30000$:
SELECT getCheapVehicleCount(30000);
The output will look into the following way:
Return multiple rows from the function
Let’s assume we need a function which returns a list of vehicles that have price lower than or equals to desired price. Such function will look into the following way:
CREATE
OR REPLACE FUNCTION getCheapVehicles(desiredPrice INTEGER)
RETURNS TABLE (id int, make VARCHAR(100), model VARCHAR(100), price NUMERIC(5)) AS $$
BEGIN
RETURN QUERY SELECT * FROM vehicle v WHERE v.price <= desiredPrice;
END;
$$
LANGUAGE plpgsql;
If we call the function getCheapVehicles
into the following way:
SELECT *
FROM getCheapVehicles(40000);
We’ll get the following output:
In case when we call getCheapVehicles
function without * FROM
we’ll get the following output:
PERFORM
When we call a function which doesn’t return any result or we don’t need the returned result we may discard result by
using PERFORM
keyword:
PERFORM
query;
More detailed information about functions in PostgreSQL could be found in official documentation here: CREATE FUNCTION.