mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-10-01 13:11:22 +02:00
766 lines
26 KiB
Plaintext
766 lines
26 KiB
Plaintext
|
|
||
|
<sect1 id="tablefunc">
|
||
|
<title>tablefunc</title>
|
||
|
|
||
|
<indexterm zone="tablefunc">
|
||
|
<primary>tablefunc</primary>
|
||
|
</indexterm>
|
||
|
|
||
|
<para>
|
||
|
<literal>tablefunc</literal> provides functions to convert query rows into fields.
|
||
|
</para>
|
||
|
<sect2>
|
||
|
<title>Functions</title>
|
||
|
<table>
|
||
|
<title></title>
|
||
|
<tgroup cols="3">
|
||
|
<thead>
|
||
|
<row>
|
||
|
<entry>Function</entry>
|
||
|
<entry>Returns</entry>
|
||
|
<entry>Comments</entry>
|
||
|
</row>
|
||
|
</thead>
|
||
|
<tbody>
|
||
|
<row>
|
||
|
<entry>
|
||
|
<literal>
|
||
|
normal_rand(int numvals, float8 mean, float8 stddev)
|
||
|
</literal>
|
||
|
</entry>
|
||
|
<entry>
|
||
|
returns a set of normally distributed float8 values
|
||
|
</entry>
|
||
|
<entry></entry>
|
||
|
</row>
|
||
|
<row>
|
||
|
<entry><literal>crosstabN(text sql)</literal></entry>
|
||
|
<entry>returns a set of row_name plus N category value columns</entry>
|
||
|
<entry>
|
||
|
crosstab2(), crosstab3(), and crosstab4() are defined for you,
|
||
|
but you can create additional crosstab functions per the instructions
|
||
|
in the documentation below.
|
||
|
</entry>
|
||
|
</row>
|
||
|
<row>
|
||
|
<entry><literal>crosstab(text sql)</literal></entry>
|
||
|
<entry>returns a set of row_name plus N category value columns</entry>
|
||
|
<entry>
|
||
|
requires anonymous composite type syntax in the FROM clause. See
|
||
|
the instructions in the documentation below.
|
||
|
</entry>
|
||
|
</row>
|
||
|
<row>
|
||
|
<entry><literal>crosstab(text sql, N int)</literal></entry>
|
||
|
<entry></entry>
|
||
|
<entry>
|
||
|
<para>obsolete version of crosstab()</para>
|
||
|
<para>
|
||
|
the argument N is now ignored, since the number of value columns
|
||
|
is always determined by the calling query
|
||
|
</para>
|
||
|
</entry>
|
||
|
</row>
|
||
|
<row>
|
||
|
<entry>
|
||
|
<literal>
|
||
|
connectby(text relname, text keyid_fld, text parent_keyid_fld
|
||
|
[, text orderby_fld], text start_with, int max_depth
|
||
|
[, text branch_delim])
|
||
|
</literal>
|
||
|
</entry>
|
||
|
<entry>
|
||
|
returns keyid, parent_keyid, level, and an optional branch string
|
||
|
and an optional serial column for ordering siblings
|
||
|
</entry>
|
||
|
<entry>
|
||
|
requires anonymous composite type syntax in the FROM clause. See
|
||
|
the instructions in the documentation below.
|
||
|
</entry>
|
||
|
</row>
|
||
|
</tbody>
|
||
|
</tgroup>
|
||
|
</table>
|
||
|
|
||
|
<sect3>
|
||
|
<title><literal>normal_rand</literal></title>
|
||
|
<programlisting>
|
||
|
normal_rand(int numvals, float8 mean, float8 stddev) RETURNS SETOF float8
|
||
|
</programlisting>
|
||
|
<para>
|
||
|
Where <literal>numvals</literal> is the number of values to be returned
|
||
|
from the function. <literal>mean</literal> is the mean of the normal
|
||
|
distribution of values and <literal>stddev</literal> is the standard
|
||
|
deviation of the normal distribution of values.
|
||
|
</para>
|
||
|
<para>
|
||
|
Returns a float8 set of random values normally distributed (Gaussian
|
||
|
distribution).
|
||
|
</para>
|
||
|
<para>
|
||
|
Example:
|
||
|
</para>
|
||
|
<programlisting>
|
||
|
test=# SELECT * FROM
|
||
|
test=# normal_rand(1000, 5, 3);
|
||
|
normal_rand
|
||
|
----------------------
|
||
|
1.56556322244898
|
||
|
9.10040991424657
|
||
|
5.36957140345079
|
||
|
-0.369151492880995
|
||
|
0.283600703686639
|
||
|
.
|
||
|
.
|
||
|
.
|
||
|
4.82992125404908
|
||
|
9.71308014517282
|
||
|
2.49639286969028
|
||
|
(1000 rows)
|
||
|
</programlisting>
|
||
|
<para>
|
||
|
Returns 1000 values with a mean of 5 and a standard deviation of 3.
|
||
|
</para>
|
||
|
</sect3>
|
||
|
|
||
|
|
||
|
<sect3>
|
||
|
<title><literal>crosstabN(text sql)</literal></title>
|
||
|
<programlisting>
|
||
|
crosstabN(text sql)
|
||
|
</programlisting>
|
||
|
<para>
|
||
|
The <literal>sql</literal> parameter is a SQL statement which produces the
|
||
|
source set of data. The SQL statement must return one row_name column, one
|
||
|
category column, and one value column. <literal>row_name</literal> and
|
||
|
value must be of type text. The function returns a set of
|
||
|
<literal>row_name</literal> plus N category value columns.
|
||
|
</para>
|
||
|
<para>
|
||
|
Provided <literal>sql</literal> must produce a set something like:
|
||
|
</para>
|
||
|
<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>
|
||
|
<para>
|
||
|
The returned value is a <literal>SETOF table_crosstab_N</literal>, which
|
||
|
is defined by:
|
||
|
</para>
|
||
|
<programlisting>
|
||
|
CREATE TYPE tablefunc_crosstab_N AS (
|
||
|
row_name TEXT,
|
||
|
category_1 TEXT,
|
||
|
category_2 TEXT,
|
||
|
.
|
||
|
.
|
||
|
.
|
||
|
category_N TEXT
|
||
|
);
|
||
|
</programlisting>
|
||
|
<para>
|
||
|
for the default installed functions, where N is 2, 3, or 4.
|
||
|
</para>
|
||
|
<para>
|
||
|
e.g. the provided crosstab2 function produces a set something like:
|
||
|
</para>
|
||
|
<programlisting>
|
||
|
<== values columns ==>
|
||
|
row_name category_1 category_2
|
||
|
---------+------------+------------
|
||
|
row1 val1 val2
|
||
|
row2 val5 val6
|
||
|
</programlisting>
|
||
|
<note>
|
||
|
<orderedlist>
|
||
|
<listitem><para>The sql result must be ordered by 1,2.</para></listitem>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
The number of values columns depends on the tuple description
|
||
|
of the function's declared return type.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
Missing values (i.e. not enough adjacent rows of same row_name to
|
||
|
fill the number of result values columns) are filled in with nulls.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
Extra values (i.e. too many adjacent rows of same row_name to fill
|
||
|
the number of result values columns) are skipped.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
Rows with all nulls in the values columns are skipped.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
The installed defaults are for illustration purposes. You
|
||
|
can create your own return types and functions based on the
|
||
|
crosstab() function of the installed library. See below for
|
||
|
details.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
</orderedlist>
|
||
|
</note>
|
||
|
<para>
|
||
|
Example:
|
||
|
</para>
|
||
|
<programlisting>
|
||
|
create table ct(id serial, rowclass text, rowid text, attribute text, value text);
|
||
|
insert into ct(rowclass, rowid, attribute, value) values('group1','test1','att1','val1');
|
||
|
insert into ct(rowclass, rowid, attribute, value) values('group1','test1','att2','val2');
|
||
|
insert into ct(rowclass, rowid, attribute, value) values('group1','test1','att3','val3');
|
||
|
insert into ct(rowclass, rowid, attribute, value) values('group1','test1','att4','val4');
|
||
|
insert into ct(rowclass, rowid, attribute, value) values('group1','test2','att1','val5');
|
||
|
insert into ct(rowclass, rowid, attribute, value) values('group1','test2','att2','val6');
|
||
|
insert into ct(rowclass, rowid, attribute, value) values('group1','test2','att3','val7');
|
||
|
insert into ct(rowclass, rowid, attribute, value) values('group1','test2','att4','val8');
|
||
|
|
||
|
select * from crosstab3(
|
||
|
'select rowid, attribute, value
|
||
|
from ct
|
||
|
where rowclass = ''group1''
|
||
|
and (attribute = ''att2'' or attribute = ''att3'') order by 1,2;');
|
||
|
|
||
|
row_name | category_1 | category_2 | category_3
|
||
|
----------+------------+------------+------------
|
||
|
test1 | val2 | val3 |
|
||
|
test2 | val6 | val7 |
|
||
|
(2 rows)
|
||
|
</programlisting>
|
||
|
</sect3>
|
||
|
|
||
|
<sect3>
|
||
|
<title><literal>crosstab(text)</literal></title>
|
||
|
<programlisting>
|
||
|
crosstab(text sql)
|
||
|
crosstab(text sql, int N)
|
||
|
</programlisting>
|
||
|
<para>
|
||
|
The <literal>sql</literal> parameter is a SQL statement which produces the
|
||
|
source set of data. The SQL statement must return one
|
||
|
<literal>row_name</literal> column, one <literal>category</literal> column,
|
||
|
and one <literal>value</literal> column. <literal>N</literal> is an
|
||
|
obsolete argument; ignored if supplied (formerly this had to match the
|
||
|
number of category columns determined by the calling query).
|
||
|
</para>
|
||
|
<para>
|
||
|
</para>
|
||
|
<para>
|
||
|
e.g. provided sql must produce a set something like:
|
||
|
</para>
|
||
|
<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>
|
||
|
<para>
|
||
|
Returns a <literal>SETOF RECORD</literal>, which must be defined with a
|
||
|
column definition in the FROM clause of the SELECT statement, e.g.:
|
||
|
</para>
|
||
|
<programlisting>
|
||
|
SELECT *
|
||
|
FROM crosstab(sql) AS ct(row_name text, category_1 text, category_2 text);
|
||
|
</programlisting>
|
||
|
<para>
|
||
|
the example crosstab function produces a set something like:
|
||
|
</para>
|
||
|
<programlisting>
|
||
|
<== values columns ==>
|
||
|
row_name category_1 category_2
|
||
|
---------+------------+------------
|
||
|
row1 val1 val2
|
||
|
row2 val5 val6
|
||
|
</programlisting>
|
||
|
<para>
|
||
|
Note that it follows these rules:
|
||
|
</para>
|
||
|
<orderedlist>
|
||
|
<listitem><para>The sql result must be ordered by 1,2.</para></listitem>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
The number of values columns is determined by the column definition
|
||
|
provided in the FROM clause. The FROM clause must define one
|
||
|
row_name column (of the same datatype as the first result column
|
||
|
of the sql query) followed by N category columns (of the same
|
||
|
datatype as the third result column of the sql query). You can
|
||
|
set up as many category columns as you wish.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
Missing values (i.e. not enough adjacent rows of same row_name to
|
||
|
fill the number of result values columns) are filled in with nulls.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
Extra values (i.e. too many adjacent rows of same row_name to fill
|
||
|
the number of result values columns) are skipped.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
Rows with all nulls in the values columns are skipped.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
You can avoid always having to write out a FROM clause that defines the
|
||
|
output columns by setting up a custom crosstab function that has
|
||
|
the desired output row type wired into its definition.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
</orderedlist>
|
||
|
<para>
|
||
|
There are two ways you can set up a custom crosstab function:
|
||
|
</para>
|
||
|
<itemizedlist>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
Create a composite type to define your return type, similar to the
|
||
|
examples in the installation script. Then define a unique function
|
||
|
name accepting one text parameter and returning setof your_type_name.
|
||
|
For example, if your source data produces row_names that are TEXT,
|
||
|
and values that are FLOAT8, and you want 5 category columns:
|
||
|
</para>
|
||
|
<programlisting>
|
||
|
CREATE TYPE my_crosstab_float8_5_cols AS (
|
||
|
row_name TEXT,
|
||
|
category_1 FLOAT8,
|
||
|
category_2 FLOAT8,
|
||
|
category_3 FLOAT8,
|
||
|
category_4 FLOAT8,
|
||
|
category_5 FLOAT8
|
||
|
);
|
||
|
|
||
|
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>
|
||
|
</listitem>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
Use OUT parameters to define the return type implicitly.
|
||
|
The same example could also be done this way:
|
||
|
</para>
|
||
|
<programlisting>
|
||
|
CREATE OR REPLACE FUNCTION crosstab_float8_5_cols(IN text,
|
||
|
OUT row_name TEXT,
|
||
|
OUT category_1 FLOAT8,
|
||
|
OUT category_2 FLOAT8,
|
||
|
OUT category_3 FLOAT8,
|
||
|
OUT category_4 FLOAT8,
|
||
|
OUT category_5 FLOAT8)
|
||
|
RETURNS setof record
|
||
|
AS '$libdir/tablefunc','crosstab' LANGUAGE C STABLE STRICT;
|
||
|
</programlisting>
|
||
|
</listitem>
|
||
|
</itemizedlist>
|
||
|
<para>
|
||
|
Example:
|
||
|
</para>
|
||
|
<programlisting>
|
||
|
CREATE TABLE ct(id SERIAL, rowclass TEXT, rowid TEXT, attribute TEXT, value TEXT);
|
||
|
INSERT INTO ct(rowclass, rowid, attribute, value) VALUES('group1','test1','att1','val1');
|
||
|
INSERT INTO ct(rowclass, rowid, attribute, value) VALUES('group1','test1','att2','val2');
|
||
|
INSERT INTO ct(rowclass, rowid, attribute, value) VALUES('group1','test1','att3','val3');
|
||
|
INSERT INTO ct(rowclass, rowid, attribute, value) VALUES('group1','test1','att4','val4');
|
||
|
INSERT INTO ct(rowclass, rowid, attribute, value) VALUES('group1','test2','att1','val5');
|
||
|
INSERT INTO ct(rowclass, rowid, attribute, value) VALUES('group1','test2','att2','val6');
|
||
|
INSERT INTO ct(rowclass, rowid, attribute, value) VALUES('group1','test2','att3','val7');
|
||
|
INSERT INTO ct(rowclass, rowid, attribute, value) VALUES('group1','test2','att4','val8');
|
||
|
|
||
|
SELECT *
|
||
|
FROM crosstab(
|
||
|
'select rowid, attribute, value
|
||
|
from ct
|
||
|
where rowclass = ''group1''
|
||
|
and (attribute = ''att2'' or attribute = ''att3'') order by 1,2;', 3)
|
||
|
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)
|
||
|
</programlisting>
|
||
|
|
||
|
</sect3>
|
||
|
|
||
|
<sect3>
|
||
|
<title><literal>crosstab(text, text)</literal></title>
|
||
|
<programlisting>
|
||
|
crosstab(text source_sql, text category_sql)
|
||
|
</programlisting>
|
||
|
|
||
|
<para>
|
||
|
Where <literal>source_sql</literal> is a SQL statement which produces the
|
||
|
source set of data. The SQL statement must return one
|
||
|
<literal>row_name</literal> column, one <literal>category</literal> column,
|
||
|
and one <literal>value</literal> column. It may also have one or more
|
||
|
<emphasis>extra</emphasis> columns.
|
||
|
</para>
|
||
|
<para>
|
||
|
The <literal>row_name</literal> column must be first. The
|
||
|
<literal>category</literal> and <literal>value</literal> columns must be
|
||
|
the last two columns, in that order. <emphasis>extra</emphasis> columns must
|
||
|
be columns 2 through (N - 2), where N is the total number of columns.
|
||
|
</para>
|
||
|
<para>
|
||
|
The <emphasis>extra</emphasis> columns are assumed to be the same for all
|
||
|
rows with the same <literal>row_name</literal>. The values returned are
|
||
|
copied from the first row with a given <literal>row_name</literal> and
|
||
|
subsequent values of these columns are ignored until
|
||
|
<literal>row_name</literal> changes.
|
||
|
</para>
|
||
|
<para>
|
||
|
e.g. <literal>source_sql</literal> must produce a set something like:
|
||
|
</para>
|
||
|
<programlisting>
|
||
|
SELECT row_name, extra_col, cat, value FROM foo;
|
||
|
|
||
|
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
|
||
|
</programlisting>
|
||
|
|
||
|
<para>
|
||
|
<literal>category_sql</literal> has to be a SQL statement which produces
|
||
|
the distinct set of categories. The SQL statement must return one category
|
||
|
column only. <literal>category_sql</literal> must produce at least one
|
||
|
result row or an error will be generated. <literal>category_sql</literal>
|
||
|
must not produce duplicate categories or an error will be generated. e.g.:
|
||
|
</para>
|
||
|
<programlisting>
|
||
|
SELECT DISTINCT cat FROM foo;
|
||
|
cat
|
||
|
-------
|
||
|
cat1
|
||
|
cat2
|
||
|
cat3
|
||
|
cat4
|
||
|
</programlisting>
|
||
|
<para>
|
||
|
The function returns <literal>SETOF RECORD</literal>, which must be defined
|
||
|
with a column definition in the FROM clause of the SELECT statement, e.g.:
|
||
|
</para>
|
||
|
<programlisting>
|
||
|
SELECT * FROM crosstab(source_sql, cat_sql)
|
||
|
AS ct(row_name text, extra text, cat1 text, cat2 text, cat3 text, cat4 text);
|
||
|
</programlisting>
|
||
|
<para>
|
||
|
the example crosstab function produces a set something like:
|
||
|
</para>
|
||
|
<programlisting>
|
||
|
<== values columns ==>
|
||
|
row_name extra cat1 cat2 cat3 cat4
|
||
|
---------+-------+------+------+------+------
|
||
|
row1 extra1 val1 val2 val4
|
||
|
row2 extra2 val5 val6 val7 val8
|
||
|
</programlisting>
|
||
|
<para>
|
||
|
Note that it follows these rules:
|
||
|
</para>
|
||
|
<orderedlist>
|
||
|
<listitem><para>source_sql must be ordered by row_name (column 1).</para></listitem>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
The number of values columns is determined at run-time. The
|
||
|
column definition provided in the FROM clause must provide for
|
||
|
the correct number of columns of the proper data types.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
Missing values (i.e. not enough adjacent rows of same row_name to
|
||
|
fill the number of result values columns) are filled in with nulls.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
Extra values (i.e. source rows with category not found in category_sql
|
||
|
result) are skipped.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
Rows with a null row_name column are skipped.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
You can create predefined functions to avoid having to write out
|
||
|
the result column names/types in each query. See the examples
|
||
|
for crosstab(text).
|
||
|
</para>
|
||
|
</listitem>
|
||
|
</orderedlist>
|
||
|
|
||
|
<programlisting>
|
||
|
CREATE TABLE cth(id serial, rowid text, rowdt timestamp, attribute text, val text);
|
||
|
INSERT INTO cth VALUES(DEFAULT,'test1','01 March 2003','temperature','42');
|
||
|
INSERT INTO cth VALUES(DEFAULT,'test1','01 March 2003','test_result','PASS');
|
||
|
INSERT INTO cth VALUES(DEFAULT,'test1','01 March 2003','volts','2.6987');
|
||
|
INSERT INTO cth VALUES(DEFAULT,'test2','02 March 2003','temperature','53');
|
||
|
INSERT INTO cth VALUES(DEFAULT,'test2','02 March 2003','test_result','FAIL');
|
||
|
INSERT INTO cth VALUES(DEFAULT,'test2','02 March 2003','test_startdate','01 March 2003');
|
||
|
INSERT INTO cth VALUES(DEFAULT,'test2','02 March 2003','volts','3.1234');
|
||
|
|
||
|
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
|
||
|
);
|
||
|
rowid | rowdt | temperature | test_result | test_startdate | volts
|
||
|
-------+--------------------------+-------------+-------------+--------------------------+--------
|
||
|
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)
|
||
|
</programlisting>
|
||
|
</sect3>
|
||
|
<sect3>
|
||
|
<title>
|
||
|
<literal>connectby(text, text, text[, text], text, text, int[, text])</literal>
|
||
|
</title>
|
||
|
<programlisting>
|
||
|
connectby(text relname, text keyid_fld, text parent_keyid_fld
|
||
|
[, text orderby_fld], text start_with, int max_depth
|
||
|
[, text branch_delim])
|
||
|
</programlisting>
|
||
|
<table>
|
||
|
<title><literal>connectby</literal> parameters</title>
|
||
|
<tgroup cols="2">
|
||
|
<thead>
|
||
|
<row>
|
||
|
<entry>Parameter</entry>
|
||
|
<entry>Description</entry>
|
||
|
</row>
|
||
|
</thead>
|
||
|
<tbody>
|
||
|
<row>
|
||
|
<entry><literal>relname</literal></entry>
|
||
|
<entry>Name of the source relation</entry>
|
||
|
</row>
|
||
|
<row>
|
||
|
<entry><literal>keyid_fld</literal></entry>
|
||
|
<entry>Name of the key field</entry>
|
||
|
</row>
|
||
|
<row>
|
||
|
<entry><literal>parent_keyid_fld</literal></entry>
|
||
|
<entry>Name of the key_parent field</entry>
|
||
|
</row>
|
||
|
<row>
|
||
|
<entry><literal>orderby_fld</literal></entry>
|
||
|
<entry>
|
||
|
If optional ordering of siblings is desired: Name of the field to
|
||
|
order siblings
|
||
|
</entry>
|
||
|
</row>
|
||
|
<row>
|
||
|
<entry><literal>start_with</literal></entry>
|
||
|
<entry>
|
||
|
Root value of the tree input as a text value regardless of
|
||
|
<literal>keyid_fld</literal>
|
||
|
</entry>
|
||
|
</row>
|
||
|
<row>
|
||
|
<entry><literal>max_depth</literal></entry>
|
||
|
<entry>
|
||
|
Zero (0) for unlimited depth, otherwise restrict level to this depth
|
||
|
</entry>
|
||
|
</row>
|
||
|
<row>
|
||
|
<entry><literal>branch_delim</literal></entry>
|
||
|
<entry>
|
||
|
If optional branch value is desired, this string is used as the delimiter.
|
||
|
When not provided, a default value of '~' is used for internal
|
||
|
recursion detection only, and no "branch" field is returned.
|
||
|
</entry>
|
||
|
</row>
|
||
|
</tbody>
|
||
|
</tgroup>
|
||
|
</table>
|
||
|
<para>
|
||
|
The function returns <literal>SETOF RECORD</literal>, which must defined
|
||
|
with a column definition in the FROM clause of the SELECT statement, e.g.:
|
||
|
</para>
|
||
|
<programlisting>
|
||
|
SELECT * FROM connectby('connectby_tree', 'keyid', 'parent_keyid', 'row2', 0, '~')
|
||
|
AS t(keyid text, parent_keyid text, level int, branch text);
|
||
|
</programlisting>
|
||
|
<para>
|
||
|
or
|
||
|
</para>
|
||
|
<programlisting>
|
||
|
SELECT * FROM connectby('connectby_tree', 'keyid', 'parent_keyid', 'row2', 0)
|
||
|
AS t(keyid text, parent_keyid text, level int);
|
||
|
</programlisting>
|
||
|
<para>
|
||
|
or
|
||
|
</para>
|
||
|
<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>
|
||
|
<para>
|
||
|
or
|
||
|
</para>
|
||
|
<programlisting>
|
||
|
SELECT * FROM connectby('connectby_tree', 'keyid', 'parent_keyid', 'pos', 'row2', 0)
|
||
|
AS t(keyid text, parent_keyid text, level int, pos int);
|
||
|
</programlisting>
|
||
|
<para>
|
||
|
Note that it follows these rules:
|
||
|
</para>
|
||
|
<orderedlist>
|
||
|
<listitem><para>keyid and parent_keyid must be the same data type</para></listitem>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
The column definition *must* include a third column of type INT4 for
|
||
|
the level value output
|
||
|
</para>
|
||
|
</listitem>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
If the branch field is not desired, omit both the branch_delim input
|
||
|
parameter *and* the branch field in the query column definition. Note
|
||
|
that when branch_delim is not provided, a default value of '~' is used
|
||
|
for branch_delim for internal recursion detection, even though the branch
|
||
|
field is not returned.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
If the branch field is desired, it must be the fourth column in the query
|
||
|
column definition, and it must be type TEXT.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
The parameters representing table and field names must include double
|
||
|
quotes if the names are mixed-case or contain special characters.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
If sorting of siblings is desired, the orderby_fld input parameter *and*
|
||
|
a name for the resulting serial field (type INT32) in the query column
|
||
|
definition must be given.
|
||
|
</para>
|
||
|
</listitem>
|
||
|
</orderedlist>
|
||
|
<para>
|
||
|
Example:
|
||
|
</para>
|
||
|
<programlisting>
|
||
|
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);
|
||
|
|
||
|
-- with branch, without orderby_fld
|
||
|
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)
|
||
|
|
||
|
-- without branch, without orderby_fld
|
||
|
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, '~')
|
||
|
AS t(keyid text, parent_keyid text, level int, branch text, pos int) ORDER BY t.pos;
|
||
|
keyid | parent_keyid | level | branch | pos
|
||
|
-------+--------------+-------+---------------------+-----
|
||
|
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)
|
||
|
AS t(keyid text, parent_keyid text, level int, pos int) ORDER BY t.pos;
|
||
|
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)
|
||
|
</programlisting>
|
||
|
</sect3>
|
||
|
</sect2>
|
||
|
<sect2>
|
||
|
<title>Author</title>
|
||
|
<para>
|
||
|
Joe Conway
|
||
|
</para>
|
||
|
</sect2>
|
||
|
</sect1>
|
||
|
|