Does any one know how to create crosstab queries in PostgreSQL?
For example I have the following table:
Section Status Count
A Active 1
A Inactive 2
B Active 4
B Inactive 5
I would like the query to return the following crosstab:
Section Active Inactive
A 1 2
B 4 5
Is this possible?
Install the additional module
tablefunc
once per database, which provides the functioncrosstab()
. Since Postgres 9.1 you can useCREATE EXTENSION
for that:Improved test case
Simple form - not fit for missing attributes
crosstab(text)
with 1 input parameter:Returns:
C
: the value7
is filled in for the first column. Sometimes, this behavior is desirable, but not for this use case.Safe form
crosstab(text, text)
with 2 input parameters:Returns:
Note the correct result for
C
.The second parameter can be any query that returns one row per attribute matching the order of the column definition at the end. Often you will want to query distinct attributes from the underlying table like this:
That's in the manual.
Since you have to spell out all columns in a column definition list anyway (except for pre-defined
crosstabN()
variants), it is typically more efficient to provide a short list in aVALUES
expression like demonstrated:Or (not in the manual):
I used dollar quoting to make quoting easier.
You can even output columns with different data types with
crosstab(text, text)
- as long as the text representation of the value column is valid input for the target type. This way you might have attributes of different kind and outputtext
,date
,numeric
etc. for respective attributes. There is a code example at the end of the chaptercrosstab(text, text)
in the manual.db<>fiddle here
Advanced examples
Pivot on Multiple Columns using Tablefunc - also demonstrating mentioned "extra columns"
Dynamic alternative to pivot with CASE and GROUP BY
\crosstabview
in psqlPostgres 9.6 added this meta-command to its default interactive terminal psql. You can run the query you would use as first
crosstab()
parameter and feed it to\crosstabview
(immediately or in the next step). Like:Similar result as above, but it's a representation feature on the client side exclusively. Input rows are treated slightly differently, hence
ORDER BY
is not required. Details for\crosstabview
in the manual. There are more code examples at the bottom of that page.Related answer on dba.SE by Daniel Vérité (the author of the psql feature):
The previously accepted answer is outdated.
The variant of the function
crosstab(text, integer)
is outdated. The secondinteger
parameter is ignored. I quote the current manual:Needless casting and renaming.
It fails if a row does not have all attributes. See safe variant with two input parameters above to handle missing attributes properly.
ORDER BY
is required in the one-parameter form ofcrosstab()
. The manual:Solution with JSON aggregation:
Sorry this isn't complete because I can't test it here, but it may get you off in the right direction. I'm translating from something I use that makes a similar query:
The code I'm working from is:
which will return a typeID, the highest price bid and the lowest price asked and the difference between the two (a positive difference would mean something could be bought for less than it can be sold).
Crosstab
function is available under thetablefunc
extension. You'll have to create this extension one time for the database.CREATE EXTENSION
tablefunc
;You can use the below code to create pivot table using cross tab:
You can use the
crosstab()
function of the additional module tablefunc - which you have to install once per database. Since PostgreSQL 9.1 you can useCREATE EXTENSION
for that:In your case, I believe it would look something like this: