<programlisting>
SELECT DISTINCT cat FROM foo ORDER BY 1;
cat
-------
cat1
cat2
cat3
cat4
</programlisting>
</para>
<para>
The <function>crosstab</function> function is declared to return <type>setof
record</type>, so the actual names and types of the output columns must be
defined in the <literal>FROM</literal> clause of the calling <command>SELECT</command>
statement, for example:
<programlisting>
SELECT * FROM crosstab('...', '...')
AS ct(row_name text, extra text, cat1 text, cat2 text, cat3 text, cat4 text);
</programlisting>
</para>
<para>
This will produce a result something like:
<programlisting>
<== value columns ==>
row_name extra cat1 cat2 cat3 cat4
---------+-------+------+------+------+------
row1 extra1 val1 val2 val4
row2 extra2 val5 val6 val7 val8
</programlisting>
</para>
<para>
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>
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>
The <function>crosstab</function> function produces one output row for each
consecutive group of input rows with the same
<structfield>row_name</structfield> value. The output
<structfield>row_name</structfield> column, plus any <quote>extra</quote>
columns, are copied from the first row of the group. The output
<structfield>value</structfield> columns are filled with the
<structfield>value</structfield> fields from rows having matching
<structfield>category</structfield> values. If a row's <structfield>category</structfield>
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
specify <literal>ORDER BY 1</literal> to ensure that values with the same
<structfield>row_name</structfield> are brought together. However,
ordering of the categories within a group is not important.
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>
<para>
Here are two complete examples:
<programlisting>
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)
</programlisting>
<programlisting>
CREATE TABLE cth(rowid text, rowdt timestamp, attribute text, val text);
INSERT INTO cth VALUES('test1','01