Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Postgres - Transpose Rows to Columns

I have the following table, which gives multiple email addresses for each user.

enter image description here

I need to flatten this out to columns on a user query. To give me the "newest" 3 email addresses based on the creation date.

user.name | user.id | email1          | email2           | email3**  Mary      | 123     | [email protected]  | [email protected] | [email protected]  Joe       | 345     | [email protected]   | [NULL]           | [NULL] 
like image 755
dacology Avatar asked Apr 14 '14 12:04

dacology


People also ask

What is crosstab in PostgreSQL?

The crosstab function produces one output row for each consecutive group of input rows with the same row_name value. The output row_name column, plus any “extra” columns, are copied from the first row of the group. The output value columns are filled with the value fields from rows having matching category values.

Does Postgres have pivot?

In PostgreSQL, pivot tables are created with the help of the crosstab() function, which is part of the optional tablefunc module. To start using this function, you need to install the tablefunc module for a required database.

What is Unnest in PostgreSQL?

PostgreSQL UNNEST() function This function is used to expand an array to a set of rows.


1 Answers

Use crosstab() from the tablefunc module.

SELECT * FROM crosstab(    $$SELECT user_id, user_name, rn, email_address      FROM  (         SELECT u.user_id, u.user_name, e.email_address              , row_number() OVER (PARTITION BY u.user_id                             ORDER BY e.creation_date DESC NULLS LAST) AS rn         FROM   usr u         LEFT   JOIN email_tbl e USING (user_id)         ) sub      WHERE  rn < 4      ORDER  BY user_id    $$   , 'VALUES (1),(2),(3)'    ) AS t (user_id int, user_name text, email1 text, email2 text, email3 text); 

I used dollar-quoting for the first parameter, which has no special meaning. It's just convenient to escape single quotes in the query string, which is a common case:

  • Insert text with single quotes in PostgreSQL

Detailed explanation and instructions:

  • PostgreSQL Crosstab Query

And in particular, for "extra columns":

  • Pivot on Multiple Columns using Tablefunc

The special difficulties here are:

  • The lack of key names.
    --> We substitute with row_number() in a subquery.

  • The varying number of emails.
    --> We limit to a max. of three in the outer SELECT
    and use crosstab() with two parameters, providing a list of possible keys.

Pay attention to NULLS LAST in the ORDER BY.

like image 91
Erwin Brandstetter Avatar answered Sep 23 '22 14:09

Erwin Brandstetter