Table functions
Overview
Table functions return multiple rows from one
input row. They are typically used in the FROM clause, where their arguments
are allowed to refer to columns of earlier tables in the FROM clause.
For example, consider the following table whose rows consist of lists of integers:
CREATE TABLE quizzes(scores int list);
INSERT INTO quizzes VALUES (LIST[5, 7, 8]), (LIST[3, 3]);
Query the scores column from the table:
SELECT scores
FROM quizzes;
The query returns two rows, where each row is a list:
scores
---------
{3,3}
{5,7,8}
(2 rows)
Now, apply the unnest table function to expand the
scores list into a collection of rows, where each row contains one list item:
SELECT scores, score
FROM
quizzes,
unnest(scores) AS score; -- In Materialize, shorthand for AS t(score)
The query returns 5 rows, one row for each list item:
scores | score
---------+-------
{3,3} | 3
{3,3} | 3
{5,7,8} | 5
{5,7,8} | 7
{5,7,8} | 8
(5 rows)
scores column is included in the
results (i.e., query projection). In practice, you generally would omit
including the original list to minimize the return data size.
WITH ORDINALITY
When a table function is used in the FROM clause, you can add WITH ORDINALITY after the table function call. WITH ORDINALITY adds a column that
includes the 1-based numbering for each output row, restarting at 1 for
each input row.
The following example uses unnest(...) WITH ORDINALITY to include the ordinality column containing the 1-based numbering of the unnested items:
SELECT scores, score, ordinality
FROM
quizzes,
unnest(scores) WITH ORDINALITY AS t(score,ordinality);
The results includes the ordinality column:
scores | score | ordinality
---------+-------+------------
{3,3} | 3 | 1
{3,3} | 3 | 2
{5,7,8} | 5 | 1
{5,7,8} | 7 | 2
{5,7,8} | 8 | 3
(5 rows)
Table- and column aliases
You can use table- and column aliases to name both the result column(s) of a table function as well as the ordinality column, if present. For example:
SELECT scores, t.score, t.listidx
FROM
quizzes,
unnest(scores) WITH ORDINALITY AS t(score,listidx);
You can also name fewer columns in the column alias list than the number of
columns in the output of the table function (plus WITH ORDINALITY, if
present), in which case the extra columns retain their original names.
ROWS FROM
When you select from multiple relations without specifying a relationship, you
get a cross join. This is also the case when you select from multiple table
functions in FROM without specifying a relationship.
For example, consider the following query that selects from two table functions without a relationship:
SELECT *
FROM
generate_series(1, 2) AS g1,
generate_series(6, 7) AS g2;
The query returns every combination of rows from both:
g1 | g2
----+----
1 | 6
1 | 7
2 | 6
2 | 7
(4 rows)
Using ROWS FROM clause with the multiple table functions, you can zip the
outputs of the table functions (i.e., combine the n-th output row from each
table function into a single row) instead of the cross product.
That is, combine first output rows of all the table functions into the first row, the second output rows of all the table functions are combined into
a second row, and so on.
For example, modify the previous query to use ROWS FROM with the table
functions:
SELECT *
FROM
ROWS FROM (
generate_series(1, 2),
generate_series(6, 7)
) AS t(g1, g2);
Instead of the cross product, the results are the “zipped” rows:
g1 | g2
----+----
1 | 6
2 | 7
(2 rows)
If the table functions in a ROWS FROM clause produce a different number of
rows, nulls are used for padding:
SELECT *
FROM
ROWS FROM (
generate_series(1, 3), -- 3 rows
generate_series(6, 7) -- 2 rows
) AS t(g1, g2);
The row with the g1 value of 3 has a null g2 value (note that if using psql,
psql prints null as an empty string):
| g1 | g2 |
| -- | ---- |
| 3 | null |
| 1 | 6 |
| 2 | 7 |
(3 rows)
For ROWS FROM clauses:
- you can use
WITH ORDINALITYon the entireROWS FROMclause, not on the individual table functions within theROWS FROMclause. - you can use table- and column aliases only on the entire
ROWS FROMclause, not on the individual table functions withinROWS FROMclause.
For example:
SELECT *
FROM
ROWS FROM (
generate_series(5, 6),
generate_series(8, 9)
) WITH ORDINALITY AS t(g1, g2, o);
The results contain the ordinality value in the o column:
g1 | g2 | o
----+----+---
5 | 8 | 1
6 | 9 | 2
(2 rows)
Table functions in the SELECT clause
You can call table functions in the SELECT clause. These will be executed as if they were at the end of the FROM clause, but their output columns will be at the appropriate position specified by their positions in the SELECT clause.
However, table functions in a SELECT clause have a number of restrictions (similar to Postgres):
- If there are multiple table functions in the
SELECTclause, they are executed as if in an implicitROWS FROMclause. WITH ORDINALITYand (explicit)ROWS FROMare not allowed.- You can give a table function call a column alias, but not a table alias.
- If there are multiple output columns of a table function (e.g.,
regexp_extracthas an output column per capture group), these will be combined into a single column, with a record type.
Tabletized scalar functions
You can also call ordinary scalar functions in the FROM clause as if they were table functions. In that case, their output will be considered a table with a single row and column.
See also
See a list of table functions in the function reference.