Summary: in this tutorial, you’ll learn how to use the PostgreSQL CREATE FUNCTION
statement to create a user-defined function.
Getting Started with the PostgreSQL CREATE FUNCTION statement #
A function is a reusable piece of code that performs a specific task. For example, the CONCAT()
function allows you to concatenate two or more strings into one string. The CONCAT()
is a built-in function provided by PostgreSQL.
PostgreSQL allows you to create a new function using the CREATE FUNCTION
statement. This function is called a user-defined function because it is created by you and other developers, not provided by PostgreSQL out of the box.
A user-defined function is a custom function that does a specific task like a built-in function.
This function takes input parameters, executes one or more SQL statements, and returns one or multiple values.
Typically, you write a user-defined function to encapsulate complex logic and make it reusable within the database.
The following shows the basic syntax of the CREATE FUNCTION
statement:
CREATE [OR REPLACE] FUNCTION function_name (parameters)
RETURNS return_type
AS
$$
-- function body
$$
LANGUAGE SQL;
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
In this syntax:
CREATE [OR REPLACE] FUNCTION
instructs PostgreSQL to create a new function. If the function name already exists, theOR REPLACE
option replaces it.function_name (parameters)
is the function name followed by parameters.RETURNS return_type
specifies the data type of a value the function will return. If the function returns no value, thereturn_type
isVOID
.AS $$ ... $$
indicates the function body enclosed within dollar-quoted strings ($$
).LANGUAGE SQL
specifies that the function is usingSQL
. Besides SQL, you can use other procedure programming languages such as PL/pgSQL.
Dollar-Quoted String Literal ($$) #
PostgreSQL requires a function body as a string. If you use regular strings, you need to escape quotes and other special characters.
To make the function body more readable, PostgreSQL offers dollar-quoted string syntax:
$tag$<string_constant>$tag$
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
In this syntax:
- The
tag
is an optional identifier. - Between
$tag$
s, you can place a string constant, which is the function body. And you don’t have to escape quotes or special characters.
Calling a user-defined function #
To call a user-defined function, you use the SELECT
statement, followed by the function name and arguments:
SELECT function_name(arguments);
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
In this syntax, the arguments
can be one or more arguments corresponding to parameters defined in the function_name
.
PostgreSQL CREATE FUNCTION statement examples #
Let’s explore some examples of creating new user-defined functions.
Creating a function that returns no value #
The following example uses the CREATE FUNCTION
statement to create a function that adds a new warehouse with name and location:
CREATE OR REPLACE FUNCTION add_warehouse (
name VARCHAR,
location VARCHAR
)
RETURNS VOID
AS
$$
INSERT INTO warehouses(warehouse_name, address)
VALUES(name,location);
$$
LANGUAGE SQL;
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
The add_warehouse
function takes two parameters:
name
with the typeVARCHAR
, which indicates the warehouse name.location
has the sameVARCHAR
data type, which indicates the warehouse’s address.
You cannot use the parameter names the same as the column names of tables used inside the function. If you do so, PostgreSQL will issue an error. The reason is that PostgreSQL will confuse the parameters and column names.
The RETURNS VOID
indicates the add_warehouse
function does not return any value.
Notice that the RETURNS
keyword includes the letter S
, not RETURN
.
The AS
keyword tells the start of the function’s body.
Between the $$
is a dollar-quoted string that represents the function body.
Inside the function body, we use an INSERT
statement that inserts a new row into the warehouses
table:
INSERT INTO warehouses (warehouse_name, address)
VALUES(name, location);
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
In the VALUES
clause, we use the parameters name
and location
.
The LANGUAGE SQL
clause indicates that the function uses SQL.
Note that you can write all the code in lowercase, including keywords like create or replace function
.
Calling the add_warehouse function #
First, call the add_warehouse
function to add a new warehouse to the warehouses
table:
SELECT
add_warehouse (
'San Mateo',
'2222 S Delaware St, San Mateo, CA 94403'
);
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
Second, retrieve data from the warehouses
table to verify the function call:
SELECT
warehouse_name,
address
FROM
warehouses;
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
Output:
warehouse_name | address
-------------------------+-------------------------------------------------
San Jose Warehouse | 205 E Alma Ave, San Jose, CA 95112
San Francisco Warehouse | 233 E Harris Ave, South San Francisco, CA 94080
Los Angeles Warehouse | 1919 Vineburn Avenue, Los Angeles, CA 90032
San Mateo | 2222 S Delaware St, San Mateo, CA 94403
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
The output shows the new warehouse in the warehouses
table.
Creating a function that returns a single value #
The following example uses the CREATE FUNCTION
statement to create a get_inventory_amount()
that returns the total inventory amount:
CREATE OR REPLACE FUNCTION get_inventory_amount ()
RETURNS DEC
AS
$$
SELECT
SUM(quantity * price)
FROM
inventories
JOIN products USING (product_id);
$$
LANGUAGE SQL;
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
In this example, the get_inventory_amount()
function has no parameter and returns a number with the type DECIMAL
or DEC
in short.
The get_inventory_amount
function executes an SQL statement that joins the inventories
and products
tables and calculates the total inventory amount using the SUM
aggregate function.
The following statement calls the get_inventory_amount()
function:
SELECT
get_inventory_amount () AS inventory_amount;
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
Output:
inventory_amount
------------------
6843946.40
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
Creating a function that returns a table #
The following statement uses the CREATE TABLE
statement to create a function get_inventory_amount_by_warehouses
that returns the inventory amounts by warehouses:
CREATE OR REPLACE FUNCTION get_inventory_amount_by_warehouses ()
RETURNS TABLE (
warehouse_name VARCHAR,
amount DEC
)
AS
$$
SELECT
warehouse_name,
SUM(quantity * price) AS amount
FROM
inventories
JOIN products USING (product_id)
JOIN warehouses USING(warehouse_id)
GROUP BY warehouse_name
ORDER BY warehouse_name;
$$
LANGUAGE SQL;
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
The get_inventory_amount_by_warehouses
function’s return type is a table with two columns:
warehouse_name
amount
The function executes a query that returns a result set with the columns corresponding to the table column in the RETURNS
clause.
The following statement calls the get_inventory_amount_by_warehouses()
function:
SELECT * FROM get_inventory_amount_by_warehouses();
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
Output:
warehouse_name | amount
-------------------------+------------
Los Angeles Warehouse | 2379982.20
San Francisco Warehouse | 2419483.10
San Jose Warehouse | 2044481.10
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
Since the function returns a table, you can place it in the FROM
clause.
If you call the function in the SELECT
clause, it’ll return a table of three rows. Each row contains a value of a composite type that consists of two fields warehouse_name
and amount
:
SELECT
get_inventory_amount_by_warehouses ();
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
Output:
get_inventory_amount_by_warehouses
----------------------------------------
("Los Angeles Warehouse",2379982.20)
("San Francisco Warehouse",2419483.10)
("San Jose Warehouse",2044481.10)
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
Creating a function that returns a value of a composite type. #
In PostgreSQL, you can define a composite type that groups multiple fields into a single unit. The PostgreSQL composite type works like a record or struct in other programming languages.
First, define a composite type called product_info
that consists of the product name and price:
CREATE TYPE product_info AS (
product_name VARCHAR,
price DECIMAL
);
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
Second, create a function that returns a value of the product_info
composite type:
CREATE OR REPLACE FUNCTION get_product_info (id INT)
RETURNS product_info
AS
$$
SELECT product_name, price
FROM products
WHERE product_id = id;
$$
LANGUAGE SQL;
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
In this example, the function get_product_info
returns a value of the composite type product_info
, which includes product_name
and price
.
Third, call the get_product_info
to retrieve the information of the product id 1:
SELECT get_product_info(1);
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
Output:
get_product_info
-------------------------------
("Samsung Galaxy S24",999.99)
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
The statement returns a value of the product_info
composite type.
To select fields from this composite value, you can place the function call in the FROM
clause:
SELECT * FROM get_product_info(1);
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
Output:
product_name | price
--------------------+--------
Samsung Galaxy S24 | 999.99
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
Summary #
- Use the
CREATE FUNCTION
statement to create a new user-defined function.