2014-04-14 20 views

risposta

33

Usa crosstab() dal modulo tablefunc.

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); 

Ho utilizzato la quotazione del dollaro per il primo parametro, che non ha significato speciale. E 'solo conveniente se si dispone di fuggire apici nella stringa di query, che è un caso comune:

spiegazione dettagliata e le istruzioni qui:

E in particolare, per "colonne extra":

I particolari difficoltà qui sono:

  • La mancanza di nomi chiave.
    -> Sostituiamo con row_number() in una sottoquery.

  • Il numero variabile di e-mail.
    -> Ci limitiamo a un max. di tre nell'esterno SELECT
    e utilizzare crosstab() con due parametri, fornendo un elenco di possibili chiavi.

Prestare attenzione a NULLS LAST in the ORDER BY.

+2

perfetto, grazie. Fa esattamente quello di cui ho bisogno. Questa domanda sarebbe stata un po 'oltre me, ma mi ha aiutato a imparare e capire molto. – dacology

+0

Per quei pochi che si chiedono. No, questo non funziona su AWS Redshift. –

+0

@MarcelloGrechiLins: queste domande e risposte sono per Postgres, non Redshift. –

8

Se qualcun altro che trova questa domanda e ha bisogno di una soluzione dinamica per questo in cui si dispone di un numero indefinito di colonne di trasporre per e non esattamente 3, è possibile trovare una bella soluzione qui: https://github.com/jumpstarter-io/colpivot