2010-09-20 22:08:53 +02:00
|
|
|
<!-- doc/src/sgml/tablefunc.sgml -->
|
2007-11-11 00:30:46 +01:00
|
|
|
|
2011-05-08 04:29:20 +02:00
|
|
|
<sect1 id="tablefunc" xreflabel="tablefunc">
|
2007-11-11 00:30:46 +01:00
|
|
|
<title>tablefunc</title>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<indexterm zone="tablefunc">
|
|
|
|
<primary>tablefunc</primary>
|
|
|
|
</indexterm>
|
|
|
|
|
|
|
|
<para>
|
2017-10-09 03:44:17 +02:00
|
|
|
The <filename>tablefunc</filename> module includes various functions that return
|
2007-12-06 05:12:10 +01:00
|
|
|
tables (that is, multiple rows). These functions are useful both in their
|
|
|
|
own right and as examples of how to write C functions that return
|
|
|
|
multiple rows.
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2020-02-13 21:02:35 +01:00
|
|
|
<para>
|
|
|
|
This module is considered <quote>trusted</quote>, that is, it can be
|
|
|
|
installed by non-superusers who have <literal>CREATE</literal> privilege
|
|
|
|
on the current database.
|
|
|
|
</para>
|
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<sect2>
|
2007-12-06 05:12:10 +01:00
|
|
|
<title>Functions Provided</title>
|
|
|
|
|
2010-08-10 22:42:01 +02:00
|
|
|
<para>
|
2020-05-07 20:25:18 +02:00
|
|
|
<xref linkend="tablefunc-functions"/> summarizes the functions provided
|
2010-08-10 22:42:01 +02:00
|
|
|
by the <filename>tablefunc</filename> module.
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<table id="tablefunc-functions">
|
2017-10-09 03:44:17 +02:00
|
|
|
<title><filename>tablefunc</filename> Functions</title>
|
2020-05-07 20:25:18 +02:00
|
|
|
<tgroup cols="1">
|
|
|
|
<thead>
|
|
|
|
<row>
|
|
|
|
<entry role="func_table_entry"><para role="func_signature">
|
|
|
|
Function
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
2020-05-07 20:25:18 +02:00
|
|
|
<para>
|
|
|
|
Description
|
|
|
|
</para></entry>
|
|
|
|
</row>
|
|
|
|
</thead>
|
|
|
|
|
|
|
|
<tbody>
|
|
|
|
<row>
|
|
|
|
<entry role="func_table_entry"><para role="func_signature">
|
|
|
|
<function>normal_rand</function> ( <parameter>numvals</parameter> <type>integer</type>, <parameter>mean</parameter> <type>float8</type>, <parameter>stddev</parameter> <type>float8</type> )
|
|
|
|
<returnvalue>setof float8</returnvalue>
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
Produces a set of normally distributed random values.
|
|
|
|
</para></entry>
|
|
|
|
</row>
|
|
|
|
|
|
|
|
<row>
|
|
|
|
<entry role="func_table_entry"><para role="func_signature">
|
|
|
|
<function>crosstab</function> ( <parameter>sql</parameter> <type>text</type> )
|
|
|
|
<returnvalue>setof record</returnvalue>
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
Produces a <quote>pivot table</quote> containing
|
|
|
|
row names plus <replaceable>N</replaceable> value columns, where
|
|
|
|
<replaceable>N</replaceable> is determined by the row type specified
|
|
|
|
in the calling query.
|
|
|
|
</para></entry>
|
|
|
|
</row>
|
|
|
|
|
|
|
|
<row>
|
|
|
|
<entry role="func_table_entry"><para role="func_signature">
|
|
|
|
<function>crosstab<replaceable>N</replaceable></function> ( <parameter>sql</parameter> <type>text</type> )
|
|
|
|
<returnvalue>setof table_crosstab_<replaceable>N</replaceable></returnvalue>
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
Produces a <quote>pivot table</quote> containing
|
|
|
|
row names plus <replaceable>N</replaceable> value columns.
|
|
|
|
<function>crosstab2</function>, <function>crosstab3</function>, and
|
|
|
|
<function>crosstab4</function> are predefined, but you can create additional
|
|
|
|
<function>crosstab<replaceable>N</replaceable></function> functions as described below.
|
|
|
|
</para></entry>
|
|
|
|
</row>
|
|
|
|
|
|
|
|
<row>
|
|
|
|
<entry role="func_table_entry"><para role="func_signature">
|
|
|
|
<function>crosstab</function> ( <parameter>source_sql</parameter> <type>text</type>, <parameter>category_sql</parameter> <type>text</type> )
|
|
|
|
<returnvalue>setof record</returnvalue>
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
Produces a <quote>pivot table</quote>
|
|
|
|
with the value columns specified by a second query.
|
|
|
|
</para></entry>
|
|
|
|
</row>
|
|
|
|
|
|
|
|
<row>
|
|
|
|
<entry role="func_table_entry"><para role="func_signature">
|
|
|
|
<function>crosstab</function> ( <parameter>sql</parameter> <type>text</type>, <parameter>N</parameter> <type>integer</type> )
|
|
|
|
<returnvalue>setof record</returnvalue>
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
Obsolete version of <function>crosstab(text)</function>.
|
|
|
|
The parameter <parameter>N</parameter> is now ignored, since the
|
|
|
|
number of value columns is always determined by the calling query.
|
|
|
|
</para></entry>
|
|
|
|
</row>
|
|
|
|
|
|
|
|
<row>
|
|
|
|
<entry role="func_table_entry"><para role="func_signature">
|
|
|
|
<indexterm><primary>connectby</primary></indexterm>
|
|
|
|
<function>connectby</function> ( <parameter>relname</parameter> <type>text</type>, <parameter>keyid_fld</parameter> <type>text</type>, <parameter>parent_keyid_fld</parameter> <type>text</type>
|
|
|
|
<optional>, <parameter>orderby_fld</parameter> <type>text</type> </optional>, <parameter>start_with</parameter> <type>text</type>, <parameter>max_depth</parameter> <type>integer</type>
|
|
|
|
<optional>, <parameter>branch_delim</parameter> <type>text</type> </optional> )
|
|
|
|
<returnvalue>setof record</returnvalue>
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
Produces a representation of a hierarchical tree structure.
|
|
|
|
</para></entry>
|
|
|
|
</row>
|
|
|
|
</tbody>
|
|
|
|
</tgroup>
|
2007-11-11 00:30:46 +01:00
|
|
|
</table>
|
|
|
|
|
|
|
|
<sect3>
|
2007-12-06 05:12:10 +01:00
|
|
|
<title><function>normal_rand</function></title>
|
|
|
|
|
2013-07-04 17:33:08 +02:00
|
|
|
<indexterm>
|
|
|
|
<primary>normal_rand</primary>
|
|
|
|
</indexterm>
|
|
|
|
|
2010-07-29 21:34:41 +02:00
|
|
|
<synopsis>
|
2007-12-06 05:12:10 +01:00
|
|
|
normal_rand(int numvals, float8 mean, float8 stddev) returns setof float8
|
2010-07-29 21:34:41 +02:00
|
|
|
</synopsis>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<para>
|
2017-10-09 03:44:17 +02:00
|
|
|
<function>normal_rand</function> produces a set of normally distributed random
|
2007-12-06 05:12:10 +01:00
|
|
|
values (Gaussian distribution).
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<para>
|
2007-12-06 05:12:10 +01:00
|
|
|
<parameter>numvals</parameter> is the number of values to be returned
|
|
|
|
from the function. <parameter>mean</parameter> is the mean of the normal
|
|
|
|
distribution of values and <parameter>stddev</parameter> is the standard
|
|
|
|
deviation of the normal distribution of values.
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<para>
|
2007-12-06 05:12:10 +01:00
|
|
|
For example, this call requests 1000 values with a mean of 5 and a
|
|
|
|
standard deviation of 3:
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2010-07-29 21:34:41 +02:00
|
|
|
<screen>
|
2007-12-06 05:12:10 +01:00
|
|
|
test=# SELECT * FROM normal_rand(1000, 5, 3);
|
2007-11-11 00:30:46 +01:00
|
|
|
normal_rand
|
|
|
|
----------------------
|
|
|
|
1.56556322244898
|
|
|
|
9.10040991424657
|
|
|
|
5.36957140345079
|
|
|
|
-0.369151492880995
|
|
|
|
0.283600703686639
|
|
|
|
.
|
|
|
|
.
|
|
|
|
.
|
|
|
|
4.82992125404908
|
|
|
|
9.71308014517282
|
|
|
|
2.49639286969028
|
|
|
|
(1000 rows)
|
2010-07-29 21:34:41 +02:00
|
|
|
</screen>
|
2007-11-11 00:30:46 +01:00
|
|
|
</sect3>
|
|
|
|
|
|
|
|
<sect3>
|
2007-12-06 05:12:10 +01:00
|
|
|
<title><function>crosstab(text)</function></title>
|
2007-11-11 00:30:46 +01:00
|
|
|
|
2013-07-04 17:33:08 +02:00
|
|
|
<indexterm>
|
|
|
|
<primary>crosstab</primary>
|
|
|
|
</indexterm>
|
|
|
|
|
2010-07-29 21:34:41 +02:00
|
|
|
<synopsis>
|
2007-11-11 00:30:46 +01:00
|
|
|
crosstab(text sql)
|
|
|
|
crosstab(text sql, int N)
|
2010-07-29 21:34:41 +02:00
|
|
|
</synopsis>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<para>
|
2017-10-09 03:44:17 +02:00
|
|
|
The <function>crosstab</function> function is used to produce <quote>pivot</quote>
|
2007-12-06 05:12:10 +01:00
|
|
|
displays, wherein data is listed across the page rather than down.
|
|
|
|
For example, we might have data like
|
2010-07-29 21:34:41 +02:00
|
|
|
<programlisting>
|
2007-12-06 05:12:10 +01:00
|
|
|
row1 val11
|
|
|
|
row1 val12
|
|
|
|
row1 val13
|
|
|
|
...
|
|
|
|
row2 val21
|
|
|
|
row2 val22
|
|
|
|
row2 val23
|
|
|
|
...
|
2010-07-29 21:34:41 +02:00
|
|
|
</programlisting>
|
2007-12-06 05:12:10 +01:00
|
|
|
which we wish to display like
|
2010-07-29 21:34:41 +02:00
|
|
|
<programlisting>
|
2007-12-06 05:12:10 +01:00
|
|
|
row1 val11 val12 val13 ...
|
|
|
|
row2 val21 val22 val23 ...
|
|
|
|
...
|
2010-07-29 21:34:41 +02:00
|
|
|
</programlisting>
|
2021-06-11 03:38:04 +02:00
|
|
|
The <function>crosstab</function> function takes a text parameter that is an SQL
|
2007-12-06 05:12:10 +01:00
|
|
|
query producing raw data formatted in the first way, and produces a table
|
|
|
|
formatted in the second way.
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<para>
|
2021-06-11 03:38:04 +02:00
|
|
|
The <parameter>sql</parameter> parameter is an SQL statement that produces
|
2007-12-06 05:12:10 +01:00
|
|
|
the source set of data. This statement must return one
|
|
|
|
<structfield>row_name</structfield> column, one
|
|
|
|
<structfield>category</structfield> column, and one
|
|
|
|
<structfield>value</structfield> column. <parameter>N</parameter> is an
|
|
|
|
obsolete parameter, ignored if supplied (formerly this had to match the
|
|
|
|
number of output value columns, but now that is determined by the
|
|
|
|
calling query).
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<para>
|
2007-12-06 05:12:10 +01:00
|
|
|
For example, the provided query might produce a set something like:
|
2007-11-11 00:30:46 +01:00
|
|
|
<programlisting>
|
|
|
|
row_name cat value
|
|
|
|
----------+-------+-------
|
|
|
|
row1 cat1 val1
|
|
|
|
row1 cat2 val2
|
|
|
|
row1 cat3 val3
|
|
|
|
row1 cat4 val4
|
|
|
|
row2 cat1 val5
|
|
|
|
row2 cat2 val6
|
|
|
|
row2 cat3 val7
|
|
|
|
row2 cat4 val8
|
|
|
|
</programlisting>
|
2010-07-29 21:34:41 +02:00
|
|
|
</para>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<para>
|
2017-10-09 03:44:17 +02:00
|
|
|
The <function>crosstab</function> function is declared to return <type>setof
|
2007-12-06 05:12:10 +01:00
|
|
|
record</type>, so the actual names and types of the output columns must be
|
2017-10-09 03:44:17 +02:00
|
|
|
defined in the <literal>FROM</literal> clause of the calling <command>SELECT</command>
|
2007-12-06 05:12:10 +01:00
|
|
|
statement, for example:
|
2010-07-29 21:34:41 +02:00
|
|
|
<programlisting>
|
|
|
|
SELECT * FROM crosstab('...') AS ct(row_name text, category_1 text, category_2 text);
|
|
|
|
</programlisting>
|
2007-12-06 05:12:10 +01:00
|
|
|
This example produces a set something like:
|
2010-07-29 21:34:41 +02:00
|
|
|
<programlisting>
|
2007-12-06 05:12:10 +01:00
|
|
|
<== value columns ==>
|
2010-07-29 21:34:41 +02:00
|
|
|
row_name category_1 category_2
|
|
|
|
----------+------------+------------
|
|
|
|
row1 val1 val2
|
|
|
|
row2 val5 val6
|
|
|
|
</programlisting>
|
|
|
|
</para>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<para>
|
2017-10-09 03:44:17 +02:00
|
|
|
The <literal>FROM</literal> clause must define the output as one
|
|
|
|
<structfield>row_name</structfield> column (of the same data type as the first result
|
|
|
|
column of the SQL query) followed by N <structfield>value</structfield> columns
|
2010-08-17 06:37:21 +02:00
|
|
|
(all of the same data type as the third result column of the SQL query).
|
2007-12-06 05:12:10 +01:00
|
|
|
You can set up as many output value columns as you wish. The names of the
|
|
|
|
output columns are up to you.
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
|
|
|
<para>
|
2017-10-09 03:44:17 +02:00
|
|
|
The <function>crosstab</function> function produces one output row for each
|
2007-12-06 05:12:10 +01:00
|
|
|
consecutive group of input rows with the same
|
|
|
|
<structfield>row_name</structfield> value. It fills the output
|
2017-10-09 03:44:17 +02:00
|
|
|
<structfield>value</structfield> columns, left to right, with the
|
2007-12-06 05:12:10 +01:00
|
|
|
<structfield>value</structfield> fields from these rows. If there
|
2017-10-09 03:44:17 +02:00
|
|
|
are fewer rows in a group than there are output <structfield>value</structfield>
|
2007-12-06 05:12:10 +01:00
|
|
|
columns, the extra output columns are filled with nulls; if there are
|
|
|
|
more rows, the extra input rows are skipped.
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
2017-10-09 03:44:17 +02:00
|
|
|
In practice the SQL query should always specify <literal>ORDER BY 1,2</literal>
|
2007-12-06 05:12:10 +01:00
|
|
|
to ensure that the input rows are properly ordered, that is, values with
|
|
|
|
the same <structfield>row_name</structfield> are brought together and
|
2017-10-09 03:44:17 +02:00
|
|
|
correctly ordered within the row. Notice that <function>crosstab</function>
|
2007-12-06 05:12:10 +01:00
|
|
|
itself does not pay any attention to the second column of the query
|
|
|
|
result; it's just there to be ordered by, to control the order in which
|
|
|
|
the third-column values appear across the page.
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
Here is a complete example:
|
2010-07-29 21:34:41 +02:00
|
|
|
<programlisting>
|
2007-12-06 05:12:10 +01:00
|
|
|
CREATE TABLE ct(id SERIAL, rowid TEXT, attribute TEXT, value TEXT);
|
|
|
|
INSERT INTO ct(rowid, attribute, value) VALUES('test1','att1','val1');
|
|
|
|
INSERT INTO ct(rowid, attribute, value) VALUES('test1','att2','val2');
|
|
|
|
INSERT INTO ct(rowid, attribute, value) VALUES('test1','att3','val3');
|
|
|
|
INSERT INTO ct(rowid, attribute, value) VALUES('test1','att4','val4');
|
|
|
|
INSERT INTO ct(rowid, attribute, value) VALUES('test2','att1','val5');
|
|
|
|
INSERT INTO ct(rowid, attribute, value) VALUES('test2','att2','val6');
|
|
|
|
INSERT INTO ct(rowid, attribute, value) VALUES('test2','att3','val7');
|
|
|
|
INSERT INTO ct(rowid, attribute, value) VALUES('test2','att4','val8');
|
|
|
|
|
|
|
|
SELECT *
|
|
|
|
FROM crosstab(
|
|
|
|
'select rowid, attribute, value
|
|
|
|
from ct
|
|
|
|
where attribute = ''att2'' or attribute = ''att3''
|
|
|
|
order by 1,2')
|
|
|
|
AS ct(row_name text, category_1 text, category_2 text, category_3 text);
|
|
|
|
|
|
|
|
row_name | category_1 | category_2 | category_3
|
|
|
|
----------+------------+------------+------------
|
|
|
|
test1 | val2 | val3 |
|
|
|
|
test2 | val6 | val7 |
|
|
|
|
(2 rows)
|
2010-07-29 21:34:41 +02:00
|
|
|
</programlisting>
|
|
|
|
</para>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
|
|
|
<para>
|
2017-10-09 03:44:17 +02:00
|
|
|
You can avoid always having to write out a <literal>FROM</literal> clause to
|
2007-12-06 05:12:10 +01:00
|
|
|
define the output columns, by setting up a custom crosstab function that
|
|
|
|
has the desired output row type wired into its definition. This is
|
|
|
|
described in the next section. Another possibility is to embed the
|
2017-10-09 03:44:17 +02:00
|
|
|
required <literal>FROM</literal> clause in a view definition.
|
2007-12-06 05:12:10 +01:00
|
|
|
</para>
|
|
|
|
|
2016-04-13 17:49:47 +02:00
|
|
|
<note>
|
|
|
|
<para>
|
2017-10-20 03:16:39 +02:00
|
|
|
See also the <command><link linkend="app-psql-meta-commands-crosstabview">\crosstabview</link></command>
|
2017-10-09 03:44:17 +02:00
|
|
|
command in <application>psql</application>, which provides functionality similar
|
|
|
|
to <function>crosstab()</function>.
|
2016-04-13 17:49:47 +02:00
|
|
|
</para>
|
|
|
|
</note>
|
|
|
|
|
2007-12-06 05:12:10 +01:00
|
|
|
</sect3>
|
|
|
|
|
|
|
|
<sect3>
|
2017-10-09 03:44:17 +02:00
|
|
|
<title><function>crosstab<replaceable>N</replaceable>(text)</function></title>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2013-07-04 17:33:08 +02:00
|
|
|
<indexterm>
|
|
|
|
<primary>crosstab</primary>
|
|
|
|
</indexterm>
|
|
|
|
|
2010-07-29 21:34:41 +02:00
|
|
|
<synopsis>
|
2017-10-09 03:44:17 +02:00
|
|
|
crosstab<replaceable>N</replaceable>(text sql)
|
2010-07-29 21:34:41 +02:00
|
|
|
</synopsis>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
|
|
|
<para>
|
2017-10-09 03:44:17 +02:00
|
|
|
The <function>crosstab<replaceable>N</replaceable></function> functions are examples of how
|
|
|
|
to set up custom wrappers for the general <function>crosstab</function> function,
|
2007-12-06 05:12:10 +01:00
|
|
|
so that you need not write out column names and types in the calling
|
2017-10-09 03:44:17 +02:00
|
|
|
<command>SELECT</command> query. The <filename>tablefunc</filename> module includes
|
|
|
|
<function>crosstab2</function>, <function>crosstab3</function>, and
|
|
|
|
<function>crosstab4</function>, whose output row types are defined as
|
2007-12-06 05:12:10 +01:00
|
|
|
</para>
|
|
|
|
|
2010-07-29 21:34:41 +02:00
|
|
|
<programlisting>
|
2007-12-06 05:12:10 +01:00
|
|
|
CREATE TYPE tablefunc_crosstab_N AS (
|
|
|
|
row_name TEXT,
|
|
|
|
category_1 TEXT,
|
|
|
|
category_2 TEXT,
|
|
|
|
.
|
|
|
|
.
|
|
|
|
.
|
|
|
|
category_N TEXT
|
|
|
|
);
|
2010-07-29 21:34:41 +02:00
|
|
|
</programlisting>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
|
|
|
<para>
|
|
|
|
Thus, these functions can be used directly when the input query produces
|
2017-10-09 03:44:17 +02:00
|
|
|
<structfield>row_name</structfield> and <structfield>value</structfield> columns of type
|
|
|
|
<type>text</type>, and you want 2, 3, or 4 output values columns.
|
2007-12-06 05:12:10 +01:00
|
|
|
In all other ways they behave exactly as described above for the
|
2017-10-09 03:44:17 +02:00
|
|
|
general <function>crosstab</function> function.
|
2007-12-06 05:12:10 +01:00
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
For instance, the example given in the previous section would also
|
|
|
|
work as
|
2010-07-29 21:34:41 +02:00
|
|
|
<programlisting>
|
2007-12-06 05:12:10 +01:00
|
|
|
SELECT *
|
|
|
|
FROM crosstab3(
|
|
|
|
'select rowid, attribute, value
|
|
|
|
from ct
|
|
|
|
where attribute = ''att2'' or attribute = ''att3''
|
|
|
|
order by 1,2');
|
2010-07-29 21:34:41 +02:00
|
|
|
</programlisting>
|
|
|
|
</para>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<para>
|
2007-12-06 05:12:10 +01:00
|
|
|
These functions are provided mostly for illustration purposes. You
|
|
|
|
can create your own return types and functions based on the
|
2017-10-09 03:44:17 +02:00
|
|
|
underlying <function>crosstab()</function> function. There are two ways
|
2007-12-06 05:12:10 +01:00
|
|
|
to do it:
|
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<itemizedlist>
|
|
|
|
<listitem>
|
|
|
|
<para>
|
2007-12-06 05:12:10 +01:00
|
|
|
Create a composite type describing the desired output columns,
|
2011-02-14 07:10:44 +01:00
|
|
|
similar to the examples in
|
2017-10-09 03:44:17 +02:00
|
|
|
<filename>contrib/tablefunc/tablefunc--1.0.sql</filename>.
|
2011-02-14 07:10:44 +01:00
|
|
|
Then define a
|
2017-10-09 03:44:17 +02:00
|
|
|
unique function name accepting one <type>text</type> parameter and returning
|
|
|
|
<type>setof your_type_name</type>, but linking to the same underlying
|
|
|
|
<function>crosstab</function> C function. For example, if your source data
|
|
|
|
produces row names that are <type>text</type>, and values that are
|
|
|
|
<type>float8</type>, and you want 5 value columns:
|
2010-07-29 21:34:41 +02:00
|
|
|
<programlisting>
|
|
|
|
CREATE TYPE my_crosstab_float8_5_cols AS (
|
|
|
|
my_row_name text,
|
|
|
|
my_category_1 float8,
|
|
|
|
my_category_2 float8,
|
|
|
|
my_category_3 float8,
|
|
|
|
my_category_4 float8,
|
|
|
|
my_category_5 float8
|
|
|
|
);
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2010-07-29 21:34:41 +02:00
|
|
|
CREATE OR REPLACE FUNCTION crosstab_float8_5_cols(text)
|
|
|
|
RETURNS setof my_crosstab_float8_5_cols
|
|
|
|
AS '$libdir/tablefunc','crosstab' LANGUAGE C STABLE STRICT;
|
|
|
|
</programlisting>
|
|
|
|
</para>
|
2007-11-11 00:30:46 +01:00
|
|
|
</listitem>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<listitem>
|
|
|
|
<para>
|
2017-10-09 03:44:17 +02:00
|
|
|
Use <literal>OUT</literal> parameters to define the return type implicitly.
|
2007-11-11 00:30:46 +01:00
|
|
|
The same example could also be done this way:
|
2010-07-29 21:34:41 +02:00
|
|
|
<programlisting>
|
|
|
|
CREATE OR REPLACE FUNCTION crosstab_float8_5_cols(
|
|
|
|
IN text,
|
|
|
|
OUT my_row_name text,
|
|
|
|
OUT my_category_1 float8,
|
|
|
|
OUT my_category_2 float8,
|
|
|
|
OUT my_category_3 float8,
|
|
|
|
OUT my_category_4 float8,
|
|
|
|
OUT my_category_5 float8)
|
|
|
|
RETURNS setof record
|
|
|
|
AS '$libdir/tablefunc','crosstab' LANGUAGE C STABLE STRICT;
|
|
|
|
</programlisting>
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
2010-07-29 21:34:41 +02:00
|
|
|
</para>
|
2007-11-11 00:30:46 +01:00
|
|
|
|
|
|
|
</sect3>
|
|
|
|
|
|
|
|
<sect3>
|
2007-12-06 05:12:10 +01:00
|
|
|
<title><function>crosstab(text, text)</function></title>
|
|
|
|
|
2013-07-04 17:33:08 +02:00
|
|
|
<indexterm>
|
|
|
|
<primary>crosstab</primary>
|
|
|
|
</indexterm>
|
|
|
|
|
2010-07-29 21:34:41 +02:00
|
|
|
<synopsis>
|
2007-11-11 00:30:46 +01:00
|
|
|
crosstab(text source_sql, text category_sql)
|
2010-07-29 21:34:41 +02:00
|
|
|
</synopsis>
|
2007-11-11 00:30:46 +01:00
|
|
|
|
|
|
|
<para>
|
2017-10-09 03:44:17 +02:00
|
|
|
The main limitation of the single-parameter form of <function>crosstab</function>
|
2007-12-06 05:12:10 +01:00
|
|
|
is that it treats all values in a group alike, inserting each value into
|
|
|
|
the first available column. If you want the value
|
|
|
|
columns to correspond to specific categories of data, and some groups
|
|
|
|
might not have data for some of the categories, that doesn't work well.
|
2017-10-09 03:44:17 +02:00
|
|
|
The two-parameter form of <function>crosstab</function> handles this case by
|
2007-12-06 05:12:10 +01:00
|
|
|
providing an explicit list of the categories corresponding to the
|
|
|
|
output columns.
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<para>
|
2021-06-11 03:38:04 +02:00
|
|
|
<parameter>source_sql</parameter> is an SQL statement that produces the
|
2007-12-06 05:12:10 +01:00
|
|
|
source set of data. This statement must return one
|
|
|
|
<structfield>row_name</structfield> column, one
|
|
|
|
<structfield>category</structfield> column, and one
|
|
|
|
<structfield>value</structfield> column. It may also have one or more
|
|
|
|
<quote>extra</quote> columns.
|
|
|
|
The <structfield>row_name</structfield> column must be first. The
|
|
|
|
<structfield>category</structfield> and <structfield>value</structfield>
|
|
|
|
columns must be the last two columns, in that order. Any columns between
|
|
|
|
<structfield>row_name</structfield> and
|
2017-10-09 03:44:17 +02:00
|
|
|
<structfield>category</structfield> are treated as <quote>extra</quote>.
|
2007-12-06 05:12:10 +01:00
|
|
|
The <quote>extra</quote> columns are expected to be the same for all rows
|
|
|
|
with the same <structfield>row_name</structfield> value.
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<para>
|
2007-12-06 05:12:10 +01:00
|
|
|
For example, <parameter>source_sql</parameter> might produce a set
|
|
|
|
something like:
|
2010-07-29 21:34:41 +02:00
|
|
|
<programlisting>
|
2011-05-02 18:19:48 +02:00
|
|
|
SELECT row_name, extra_col, cat, value FROM foo ORDER BY 1;
|
|
|
|
|
|
|
|
row_name extra_col cat value
|
|
|
|
----------+------------+-----+---------
|
|
|
|
row1 extra1 cat1 val1
|
|
|
|
row1 extra1 cat2 val2
|
|
|
|
row1 extra1 cat4 val4
|
|
|
|
row2 extra2 cat1 val5
|
|
|
|
row2 extra2 cat2 val6
|
|
|
|
row2 extra2 cat3 val7
|
|
|
|
row2 extra2 cat4 val8
|
2010-07-29 21:34:41 +02:00
|
|
|
</programlisting>
|
|
|
|
</para>
|
2007-11-11 00:30:46 +01:00
|
|
|
|
|
|
|
<para>
|
2021-06-11 03:38:04 +02:00
|
|
|
<parameter>category_sql</parameter> is an SQL statement that produces
|
2007-12-06 05:12:10 +01:00
|
|
|
the set of categories. This statement must return only one column.
|
|
|
|
It must produce at least one row, or an error will be generated.
|
|
|
|
Also, it must not produce duplicate values, or an error will be
|
|
|
|
generated. <parameter>category_sql</parameter> might be something like:
|
|
|
|
|
2010-07-29 21:34:41 +02:00
|
|
|
<programlisting>
|
2007-12-06 05:12:10 +01:00
|
|
|
SELECT DISTINCT cat FROM foo ORDER BY 1;
|
2007-11-11 00:30:46 +01:00
|
|
|
cat
|
|
|
|
-------
|
|
|
|
cat1
|
|
|
|
cat2
|
|
|
|
cat3
|
|
|
|
cat4
|
2010-07-29 21:34:41 +02:00
|
|
|
</programlisting>
|
|
|
|
</para>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<para>
|
2017-10-09 03:44:17 +02:00
|
|
|
The <function>crosstab</function> function is declared to return <type>setof
|
2007-12-06 05:12:10 +01:00
|
|
|
record</type>, so the actual names and types of the output columns must be
|
2017-10-09 03:44:17 +02:00
|
|
|
defined in the <literal>FROM</literal> clause of the calling <command>SELECT</command>
|
2007-12-06 05:12:10 +01:00
|
|
|
statement, for example:
|
|
|
|
|
2010-07-29 21:34:41 +02:00
|
|
|
<programlisting>
|
|
|
|
SELECT * FROM crosstab('...', '...')
|
|
|
|
AS ct(row_name text, extra text, cat1 text, cat2 text, cat3 text, cat4 text);
|
|
|
|
</programlisting>
|
|
|
|
</para>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<para>
|
2007-12-06 05:12:10 +01:00
|
|
|
This will produce a result something like:
|
2010-07-29 21:34:41 +02:00
|
|
|
<programlisting>
|
|
|
|
<== value columns ==>
|
|
|
|
row_name extra cat1 cat2 cat3 cat4
|
|
|
|
---------+-------+------+------+------+------
|
|
|
|
row1 extra1 val1 val2 val4
|
|
|
|
row2 extra2 val5 val6 val7 val8
|
|
|
|
</programlisting>
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
|
|
|
<para>
|
2017-10-09 03:44:17 +02:00
|
|
|
The <literal>FROM</literal> clause must define the proper number of output
|
|
|
|
columns of the proper data types. If there are <replaceable>N</replaceable>
|
|
|
|
columns in the <parameter>source_sql</parameter> query's result, the first
|
|
|
|
<replaceable>N</replaceable>-2 of them must match up with the first
|
|
|
|
<replaceable>N</replaceable>-2 output columns. The remaining output columns
|
|
|
|
must have the type of the last column of the <parameter>source_sql</parameter>
|
2007-12-06 05:12:10 +01:00
|
|
|
query's result, and there must be exactly as many of them as there
|
|
|
|
are rows in the <parameter>category_sql</parameter> query's result.
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
2017-10-09 03:44:17 +02:00
|
|
|
The <function>crosstab</function> function produces one output row for each
|
2007-12-06 05:12:10 +01:00
|
|
|
consecutive group of input rows with the same
|
|
|
|
<structfield>row_name</structfield> value. The output
|
2017-10-09 03:44:17 +02:00
|
|
|
<structfield>row_name</structfield> column, plus any <quote>extra</quote>
|
2007-12-06 05:12:10 +01:00
|
|
|
columns, are copied from the first row of the group. The output
|
2017-10-09 03:44:17 +02:00
|
|
|
<structfield>value</structfield> columns are filled with the
|
2007-12-06 05:12:10 +01:00
|
|
|
<structfield>value</structfield> fields from rows having matching
|
2017-10-09 03:44:17 +02:00
|
|
|
<structfield>category</structfield> values. If a row's <structfield>category</structfield>
|
2007-12-06 05:12:10 +01:00
|
|
|
does not match any output of the <parameter>category_sql</parameter>
|
|
|
|
query, its <structfield>value</structfield> is ignored. Output
|
|
|
|
columns whose matching category is not present in any input row
|
|
|
|
of the group are filled with nulls.
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
In practice the <parameter>source_sql</parameter> query should always
|
2017-10-09 03:44:17 +02:00
|
|
|
specify <literal>ORDER BY 1</literal> to ensure that values with the same
|
2007-12-06 05:12:10 +01:00
|
|
|
<structfield>row_name</structfield> are brought together. However,
|
2012-08-16 17:26:40 +02:00
|
|
|
ordering of the categories within a group is not important.
|
2007-12-06 05:12:10 +01:00
|
|
|
Also, it is essential to be sure that the order of the
|
|
|
|
<parameter>category_sql</parameter> query's output matches the specified
|
|
|
|
output column order.
|
|
|
|
</para>
|
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<para>
|
2007-12-06 05:12:10 +01:00
|
|
|
Here are two complete examples:
|
2010-07-29 21:34:41 +02:00
|
|
|
<programlisting>
|
2007-12-06 05:12:10 +01:00
|
|
|
create table sales(year int, month int, qty int);
|
|
|
|
insert into sales values(2007, 1, 1000);
|
|
|
|
insert into sales values(2007, 2, 1500);
|
|
|
|
insert into sales values(2007, 7, 500);
|
|
|
|
insert into sales values(2007, 11, 1500);
|
|
|
|
insert into sales values(2007, 12, 2000);
|
|
|
|
insert into sales values(2008, 1, 1000);
|
|
|
|
|
|
|
|
select * from crosstab(
|
|
|
|
'select year, month, qty from sales order by 1',
|
|
|
|
'select m from generate_series(1,12) m'
|
|
|
|
) as (
|
|
|
|
year int,
|
|
|
|
"Jan" int,
|
|
|
|
"Feb" int,
|
|
|
|
"Mar" int,
|
|
|
|
"Apr" int,
|
|
|
|
"May" int,
|
|
|
|
"Jun" int,
|
|
|
|
"Jul" int,
|
|
|
|
"Aug" int,
|
|
|
|
"Sep" int,
|
|
|
|
"Oct" int,
|
|
|
|
"Nov" int,
|
|
|
|
"Dec" int
|
|
|
|
);
|
|
|
|
year | Jan | Feb | Mar | Apr | May | Jun | Jul | Aug | Sep | Oct | Nov | Dec
|
|
|
|
------+------+------+-----+-----+-----+-----+-----+-----+-----+-----+------+------
|
|
|
|
2007 | 1000 | 1500 | | | | | 500 | | | | 1500 | 2000
|
|
|
|
2008 | 1000 | | | | | | | | | | |
|
|
|
|
(2 rows)
|
2010-07-29 21:34:41 +02:00
|
|
|
</programlisting>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2010-07-29 21:34:41 +02:00
|
|
|
<programlisting>
|
2007-12-06 05:12:10 +01:00
|
|
|
CREATE TABLE cth(rowid text, rowdt timestamp, attribute text, val text);
|
|
|
|
INSERT INTO cth VALUES('test1','01 March 2003','temperature','42');
|
|
|
|
INSERT INTO cth VALUES('test1','01 March 2003','test_result','PASS');
|
|
|
|
INSERT INTO cth VALUES('test1','01 March 2003','volts','2.6987');
|
|
|
|
INSERT INTO cth VALUES('test2','02 March 2003','temperature','53');
|
|
|
|
INSERT INTO cth VALUES('test2','02 March 2003','test_result','FAIL');
|
|
|
|
INSERT INTO cth VALUES('test2','02 March 2003','test_startdate','01 March 2003');
|
|
|
|
INSERT INTO cth VALUES('test2','02 March 2003','volts','3.1234');
|
2007-11-11 00:30:46 +01:00
|
|
|
|
|
|
|
SELECT * FROM crosstab
|
|
|
|
(
|
|
|
|
'SELECT rowid, rowdt, attribute, val FROM cth ORDER BY 1',
|
|
|
|
'SELECT DISTINCT attribute FROM cth ORDER BY 1'
|
|
|
|
)
|
|
|
|
AS
|
|
|
|
(
|
|
|
|
rowid text,
|
|
|
|
rowdt timestamp,
|
|
|
|
temperature int4,
|
|
|
|
test_result text,
|
|
|
|
test_startdate timestamp,
|
|
|
|
volts float8
|
|
|
|
);
|
2007-12-06 05:12:10 +01:00
|
|
|
rowid | rowdt | temperature | test_result | test_startdate | volts
|
2007-11-11 00:30:46 +01:00
|
|
|
-------+--------------------------+-------------+-------------+--------------------------+--------
|
|
|
|
test1 | Sat Mar 01 00:00:00 2003 | 42 | PASS | | 2.6987
|
|
|
|
test2 | Sun Mar 02 00:00:00 2003 | 53 | FAIL | Sat Mar 01 00:00:00 2003 | 3.1234
|
|
|
|
(2 rows)
|
2010-07-29 21:34:41 +02:00
|
|
|
</programlisting>
|
|
|
|
</para>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
|
|
|
<para>
|
|
|
|
You can create predefined functions to avoid having to write out
|
|
|
|
the result column names and types in each query. See the examples
|
|
|
|
in the previous section. The underlying C function for this form
|
2017-10-09 03:44:17 +02:00
|
|
|
of <function>crosstab</function> is named <literal>crosstab_hash</literal>.
|
2007-12-06 05:12:10 +01:00
|
|
|
</para>
|
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
</sect3>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<sect3>
|
2007-12-06 05:12:10 +01:00
|
|
|
<title><function>connectby</function></title>
|
|
|
|
|
2013-07-04 17:33:08 +02:00
|
|
|
<indexterm>
|
|
|
|
<primary>connectby</primary>
|
|
|
|
</indexterm>
|
|
|
|
|
2010-07-29 21:34:41 +02:00
|
|
|
<synopsis>
|
2007-11-11 00:30:46 +01:00
|
|
|
connectby(text relname, text keyid_fld, text parent_keyid_fld
|
2007-12-06 05:12:10 +01:00
|
|
|
[, text orderby_fld ], text start_with, int max_depth
|
|
|
|
[, text branch_delim ])
|
2010-07-29 21:34:41 +02:00
|
|
|
</synopsis>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
|
|
|
<para>
|
2017-10-09 03:44:17 +02:00
|
|
|
The <function>connectby</function> function produces a display of hierarchical
|
2007-12-06 05:12:10 +01:00
|
|
|
data that is stored in a table. The table must have a key field that
|
|
|
|
uniquely identifies rows, and a parent-key field that references the
|
2017-10-09 03:44:17 +02:00
|
|
|
parent (if any) of each row. <function>connectby</function> can display the
|
2007-12-06 05:12:10 +01:00
|
|
|
sub-tree descending from any row.
|
|
|
|
</para>
|
|
|
|
|
2010-08-10 22:42:01 +02:00
|
|
|
<para>
|
2017-11-23 15:39:47 +01:00
|
|
|
<xref linkend="tablefunc-connectby-parameters"/> explains the
|
2010-08-10 22:42:01 +02:00
|
|
|
parameters.
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<table id="tablefunc-connectby-parameters">
|
2011-01-29 19:00:18 +01:00
|
|
|
<title><function>connectby</function> Parameters</title>
|
2007-11-11 00:30:46 +01:00
|
|
|
<tgroup cols="2">
|
|
|
|
<thead>
|
|
|
|
<row>
|
|
|
|
<entry>Parameter</entry>
|
|
|
|
<entry>Description</entry>
|
|
|
|
</row>
|
|
|
|
</thead>
|
|
|
|
<tbody>
|
|
|
|
<row>
|
2007-12-06 05:12:10 +01:00
|
|
|
<entry><parameter>relname</parameter></entry>
|
2007-11-11 00:30:46 +01:00
|
|
|
<entry>Name of the source relation</entry>
|
|
|
|
</row>
|
|
|
|
<row>
|
2007-12-06 05:12:10 +01:00
|
|
|
<entry><parameter>keyid_fld</parameter></entry>
|
2007-11-11 00:30:46 +01:00
|
|
|
<entry>Name of the key field</entry>
|
|
|
|
</row>
|
|
|
|
<row>
|
2007-12-06 05:12:10 +01:00
|
|
|
<entry><parameter>parent_keyid_fld</parameter></entry>
|
|
|
|
<entry>Name of the parent-key field</entry>
|
2007-11-11 00:30:46 +01:00
|
|
|
</row>
|
|
|
|
<row>
|
2007-12-06 05:12:10 +01:00
|
|
|
<entry><parameter>orderby_fld</parameter></entry>
|
|
|
|
<entry>Name of the field to order siblings by (optional)</entry>
|
2007-11-11 00:30:46 +01:00
|
|
|
</row>
|
|
|
|
<row>
|
2007-12-06 05:12:10 +01:00
|
|
|
<entry><parameter>start_with</parameter></entry>
|
|
|
|
<entry>Key value of the row to start at</entry>
|
2007-11-11 00:30:46 +01:00
|
|
|
</row>
|
|
|
|
<row>
|
2007-12-06 05:12:10 +01:00
|
|
|
<entry><parameter>max_depth</parameter></entry>
|
|
|
|
<entry>Maximum depth to descend to, or zero for unlimited depth</entry>
|
2007-11-11 00:30:46 +01:00
|
|
|
</row>
|
|
|
|
<row>
|
2007-12-06 05:12:10 +01:00
|
|
|
<entry><parameter>branch_delim</parameter></entry>
|
|
|
|
<entry>String to separate keys with in branch output (optional)</entry>
|
2007-11-11 00:30:46 +01:00
|
|
|
</row>
|
|
|
|
</tbody>
|
|
|
|
</tgroup>
|
|
|
|
</table>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<para>
|
2007-12-06 05:12:10 +01:00
|
|
|
The key and parent-key fields can be any data type, but they must be
|
2017-10-09 03:44:17 +02:00
|
|
|
the same type. Note that the <parameter>start_with</parameter> value must be
|
2007-12-06 05:12:10 +01:00
|
|
|
entered as a text string, regardless of the type of the key field.
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<para>
|
2017-10-09 03:44:17 +02:00
|
|
|
The <function>connectby</function> function is declared to return <type>setof
|
2007-12-06 05:12:10 +01:00
|
|
|
record</type>, so the actual names and types of the output columns must be
|
2017-10-09 03:44:17 +02:00
|
|
|
defined in the <literal>FROM</literal> clause of the calling <command>SELECT</command>
|
2007-12-06 05:12:10 +01:00
|
|
|
statement, for example:
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2010-07-29 21:34:41 +02:00
|
|
|
<programlisting>
|
|
|
|
SELECT * FROM connectby('connectby_tree', 'keyid', 'parent_keyid', 'pos', 'row2', 0, '~')
|
|
|
|
AS t(keyid text, parent_keyid text, level int, branch text, pos int);
|
|
|
|
</programlisting>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<para>
|
2007-12-06 05:12:10 +01:00
|
|
|
The first two output columns are used for the current row's key and
|
|
|
|
its parent row's key; they must match the type of the table's key field.
|
|
|
|
The third output column is the depth in the tree and must be of type
|
2017-10-09 03:44:17 +02:00
|
|
|
<type>integer</type>. If a <parameter>branch_delim</parameter> parameter was
|
2007-12-06 05:12:10 +01:00
|
|
|
given, the next output column is the branch display and must be of type
|
2017-10-09 03:44:17 +02:00
|
|
|
<type>text</type>. Finally, if an <parameter>orderby_fld</parameter>
|
2007-12-06 05:12:10 +01:00
|
|
|
parameter was given, the last output column is a serial number, and must
|
2017-10-09 03:44:17 +02:00
|
|
|
be of type <type>integer</type>.
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<para>
|
2017-10-09 03:44:17 +02:00
|
|
|
The <quote>branch</quote> output column shows the path of keys taken to
|
2007-12-06 05:12:10 +01:00
|
|
|
reach the current row. The keys are separated by the specified
|
|
|
|
<parameter>branch_delim</parameter> string. If no branch display is
|
|
|
|
wanted, omit both the <parameter>branch_delim</parameter> parameter
|
|
|
|
and the branch column in the output column list.
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
|
|
|
<para>
|
|
|
|
If the ordering of siblings of the same parent is important,
|
|
|
|
include the <parameter>orderby_fld</parameter> parameter to
|
|
|
|
specify which field to order siblings by. This field can be of any
|
|
|
|
sortable data type. The output column list must include a final
|
|
|
|
integer serial-number column, if and only if
|
|
|
|
<parameter>orderby_fld</parameter> is specified.
|
|
|
|
</para>
|
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<para>
|
2007-12-06 05:12:10 +01:00
|
|
|
The parameters representing table and field names are copied as-is
|
2017-10-09 03:44:17 +02:00
|
|
|
into the SQL queries that <function>connectby</function> generates internally.
|
2007-12-06 05:12:10 +01:00
|
|
|
Therefore, include double quotes if the names are mixed-case or contain
|
|
|
|
special characters. You may also need to schema-qualify the table name.
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
|
|
|
<para>
|
|
|
|
In large tables, performance will be poor unless there is an index on
|
|
|
|
the parent-key field.
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
It is important that the <parameter>branch_delim</parameter> string
|
2017-10-09 03:44:17 +02:00
|
|
|
not appear in any key values, else <function>connectby</function> may incorrectly
|
2007-12-06 05:12:10 +01:00
|
|
|
report an infinite-recursion error. Note that if
|
|
|
|
<parameter>branch_delim</parameter> is not provided, a default value
|
2017-10-09 03:44:17 +02:00
|
|
|
of <literal>~</literal> is used for recursion detection purposes.
|
2007-12-06 05:12:10 +01:00
|
|
|
<!-- That pretty well sucks. FIXME -->
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
Here is an example:
|
2010-07-29 21:34:41 +02:00
|
|
|
<programlisting>
|
2007-11-11 00:30:46 +01:00
|
|
|
CREATE TABLE connectby_tree(keyid text, parent_keyid text, pos int);
|
|
|
|
|
|
|
|
INSERT INTO connectby_tree VALUES('row1',NULL, 0);
|
|
|
|
INSERT INTO connectby_tree VALUES('row2','row1', 0);
|
|
|
|
INSERT INTO connectby_tree VALUES('row3','row1', 0);
|
|
|
|
INSERT INTO connectby_tree VALUES('row4','row2', 1);
|
|
|
|
INSERT INTO connectby_tree VALUES('row5','row2', 0);
|
|
|
|
INSERT INTO connectby_tree VALUES('row6','row4', 0);
|
|
|
|
INSERT INTO connectby_tree VALUES('row7','row3', 0);
|
|
|
|
INSERT INTO connectby_tree VALUES('row8','row6', 0);
|
|
|
|
INSERT INTO connectby_tree VALUES('row9','row5', 0);
|
|
|
|
|
2007-12-06 05:12:10 +01:00
|
|
|
-- with branch, without orderby_fld (order of results is not guaranteed)
|
2007-11-11 00:30:46 +01:00
|
|
|
SELECT * FROM connectby('connectby_tree', 'keyid', 'parent_keyid', 'row2', 0, '~')
|
|
|
|
AS t(keyid text, parent_keyid text, level int, branch text);
|
|
|
|
keyid | parent_keyid | level | branch
|
|
|
|
-------+--------------+-------+---------------------
|
|
|
|
row2 | | 0 | row2
|
|
|
|
row4 | row2 | 1 | row2~row4
|
|
|
|
row6 | row4 | 2 | row2~row4~row6
|
|
|
|
row8 | row6 | 3 | row2~row4~row6~row8
|
|
|
|
row5 | row2 | 1 | row2~row5
|
|
|
|
row9 | row5 | 2 | row2~row5~row9
|
|
|
|
(6 rows)
|
|
|
|
|
2007-12-06 05:12:10 +01:00
|
|
|
-- without branch, without orderby_fld (order of results is not guaranteed)
|
2007-11-11 00:30:46 +01:00
|
|
|
SELECT * FROM connectby('connectby_tree', 'keyid', 'parent_keyid', 'row2', 0)
|
|
|
|
AS t(keyid text, parent_keyid text, level int);
|
|
|
|
keyid | parent_keyid | level
|
|
|
|
-------+--------------+-------
|
|
|
|
row2 | | 0
|
|
|
|
row4 | row2 | 1
|
|
|
|
row6 | row4 | 2
|
|
|
|
row8 | row6 | 3
|
|
|
|
row5 | row2 | 1
|
|
|
|
row9 | row5 | 2
|
|
|
|
(6 rows)
|
|
|
|
|
|
|
|
-- with branch, with orderby_fld (notice that row5 comes before row4)
|
|
|
|
SELECT * FROM connectby('connectby_tree', 'keyid', 'parent_keyid', 'pos', 'row2', 0, '~')
|
2007-12-06 05:12:10 +01:00
|
|
|
AS t(keyid text, parent_keyid text, level int, branch text, pos int);
|
|
|
|
keyid | parent_keyid | level | branch | pos
|
2007-11-11 00:30:46 +01:00
|
|
|
-------+--------------+-------+---------------------+-----
|
|
|
|
row2 | | 0 | row2 | 1
|
|
|
|
row5 | row2 | 1 | row2~row5 | 2
|
|
|
|
row9 | row5 | 2 | row2~row5~row9 | 3
|
|
|
|
row4 | row2 | 1 | row2~row4 | 4
|
|
|
|
row6 | row4 | 2 | row2~row4~row6 | 5
|
|
|
|
row8 | row6 | 3 | row2~row4~row6~row8 | 6
|
|
|
|
(6 rows)
|
|
|
|
|
|
|
|
-- without branch, with orderby_fld (notice that row5 comes before row4)
|
|
|
|
SELECT * FROM connectby('connectby_tree', 'keyid', 'parent_keyid', 'pos', 'row2', 0)
|
2007-12-06 05:12:10 +01:00
|
|
|
AS t(keyid text, parent_keyid text, level int, pos int);
|
2007-11-11 00:30:46 +01:00
|
|
|
keyid | parent_keyid | level | pos
|
|
|
|
-------+--------------+-------+-----
|
|
|
|
row2 | | 0 | 1
|
|
|
|
row5 | row2 | 1 | 2
|
|
|
|
row9 | row5 | 2 | 3
|
|
|
|
row4 | row2 | 1 | 4
|
|
|
|
row6 | row4 | 2 | 5
|
|
|
|
row8 | row6 | 3 | 6
|
|
|
|
(6 rows)
|
2010-07-29 21:34:41 +02:00
|
|
|
</programlisting>
|
|
|
|
</para>
|
2007-11-11 00:30:46 +01:00
|
|
|
</sect3>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
</sect2>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<sect2>
|
|
|
|
<title>Author</title>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<para>
|
|
|
|
Joe Conway
|
|
|
|
</para>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
</sect2>
|
|
|
|
|
2007-12-06 05:12:10 +01:00
|
|
|
</sect1>
|