produces one output row for each
consecutive group of input rows with the same
<structfield>row_name</structfield> value. It fills the output
<structfield>value</structfield> columns, left to right, with the
<structfield>value</structfield> fields from these rows. If there
are fewer rows in a group than there are output <structfield>value</structfield>
columns, the extra output columns are filled with nulls; if there are
more rows, the extra input rows are skipped.
</para>
<para>
In practice the SQL query should always specify <literal>ORDER BY 1,2</literal>
to ensure that the input rows are properly ordered, that is, values with
the same <structfield>row_name</structfield> are brought together and
correctly ordered within the row. Notice that <function>crosstab</function>
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:
<programlisting>
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)
</programlisting>
</para>
<para>
You can avoid always having to write out a <literal>FROM</literal> clause to
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
required <literal>FROM</literal> clause in a view definition.
</para>
<note>
<para>
See also the <command><link linkend="app-psql-meta-commands-crosstabview">\crosstabview</link></command>
command in <application>psql</application>, which provides functionality similar
to <function>crosstab()</function>.
</para>
</note>
</sect3>
<sect3 id="tablefunc-functions-crosstab-n-text">
<title><function>crosstab<replaceable>N</replaceable>(text)</function></title>
<indexterm>
<primary>crosstab</primary>
</indexterm>
<synopsis>
crosstab<replaceable>N</replaceable>(text sql)
</synopsis>
<para>
The <function>crosstab<replaceable>N</replaceable></function> functions are examples of how
to set up custom wrappers for the general <function>crosstab</function> function,
so that you need not write out column names and types in the calling
<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
</para>
<programlisting>
CREATE TYPE tablefunc_crosstab_N AS (
row_name TEXT,
category_1 TEXT,
category_2 TEXT,
.
.
.
category_N TEXT
);
</programlisting>
<para>
Thus, these functions can be used directly when the input query produces
<structfield>row_name</structfield> and <structfield>value</structfield>