PostgreSQL – Pivot Email Rows into Multiple Columns per ID

pivotpostgresqlpostgresql-13

I have a table "emails":

id email
1 a@a.a
2 g@g.g
2 d@d.d
4 c@c.c
2 k@k.k
4 o@o.o

I need this result:

id email email email
1 a@a.a
2 g@g.g d@d.d k@k.k
4 c@c.c o@o.o

the number of columns could expand in future. In fact, in the real database, I have ids with 10 emails already.

Every id, email pair is unique in the table.

I will need to join the resulant table with another table "users" on id.

I'm using Postgres 13.3

This answer is close to my needs, I just need it to be in different columns: https://stackoverflow.com/a/15847245

Best Answer

You can aggregate the emails into an array:

select id, array_agg(email) as all_emails
from the_table
group by id;

This can be used to join against the users table. To put the emails into columns, extract them from the array.

select u.*, 
       e.all_emails[1] as email1, 
       e.all_emails[2] as email2, 
       e.all_emails[3] as email3, 
       e.all_emails[4] as email4 
from users u
  join (
    select id, array_agg(email) as all_emails
    from the_table
    group by id
  ) e on e.id = u.id;

If you need more emails, add more expressions to the outer query. If an index position does not exist, null is returned instead (no error).

It is not possible to write query that dynamically returns a different number of columns each time you call it. The number, type and name of all columns of a query must be known before the query starts running.