2015-10-03 13 views
5

ho attualmente una tabella m del seguente formato:funzione Crosstab in Postgres restituire un uscita una riga quando mi aspetto più righe

id scenario period ct 
2  1   1  1 
2  1   2  1 
2  1   3  1 
2  1   4  1 
2  2   1  1 
2  2   2  1 
2  2   3  1 
2  2   4  1 
2  3   1  1 
2  3   2  1 
2  3   3  1 
2  3   4  1 

voglio creare la seguente tabella:

id scenario period 1 2 3 4 
2  1   1  1 
2  1   2   1 
2  1   3     1 
2  1   4      1 
2  2   1  1 
2  2   2   1 
2  2   3     1 
2  2   4      1 
2  3   1  1 
2  3   2   1 
2  3   3     1 
2  3   4      1 

L'estensione tablefunc è già stata creata nel mio database Postgres. Attualmente sto cercando di utilizzare la funzione crosstab() per completare il pivot. Tuttavia, sto diventando un tavolo che è simile al seguente:

id scenario period 1 2 3 4 
2  1   1  1 1 1 1 

La query ho provato:

SELECT * FROM crosstab(
     'SELECT id, scenario, period, ct FROM m 
      ORDER BY 1', 
     'SELECT DISTINCT period FROM m 
      ORDER BY 1') 
AS (id, scenario, period, 1, 2, 3, 4); 
+0

La query presentata non è valida. (l'elenco di definizioni di colonne manca di tipi di dati). Qual è la query effettiva che hai provato? –

+0

Il mio set di dati è molto più grande, ma volevo un esempio più semplice da mostrare. Credo che la domanda più corretta sarebbe: SELECT * FROM a campi incrociati ( \t \t 'SELECT id, scenario, periodo, CT da m \t \t \t ORDER BY 1', \t \t 'Seleziona il periodo DISTINTO DA m \t \t \t ORDINA DA 1 ') AS (id int, scenario int, periodo int, "1" int, "2" int, "3" int, "4" int); –

risposta

3

Questa query genera l'output desiderato:

SELECT id, scenario, period, p1, p2, p3, p4 -- all except aux column rn 
FROM crosstab(
    'SELECT row_number() OVER (ORDER BY id, scenario, period)::int AS rn 
     , id, scenario, period, period, ct 
    FROM m 
    ORDER BY 1' 
, 'VALUES (1), (2), (3), (4)' 
    ) AS (rn int, id int, scenario int, period int, p1 int, p2 int, p3 int, p4 int); 

Due particolari difficoltà :

  1. Non hai ancora un'unica colonna univoca per lo nome_riga. Io uso row_number() per generare la chiave surrogata: rn. L'ho rimosso dall'esterno SELECT per abbinare il risultato desiderato.
    Il modo in cui è stato provato, id è il nome riga e tutte le righe di input sono aggregate in un'unica riga di output.

  2. Volete colonne aggiuntive (scenario e period) nel risultato, che deve venire dopo la ROW_NAME e prima della categoria. È necessario elencare perioddue volte per ottenere la colonna originale in aggiunta - ridondante come se possa sembrare.

Basics:

relativi a questo caso particolare:


In genere, si avrebbe una query come questa:

SELECT id, scenario, p1, p2, p3, p4 -- all except aux column rn 
FROM crosstab(
    'SELECT rank() OVER (ORDER BY id, scenario)::int AS rn 
     , id, scenario, period, ct 
    FROM m 
    ORDER BY 1' 
, 'VALUES (1), (2), (3), (4)' 
    ) AS (rn int, id int, scenario int, p1 int, p2 int, p3 int, p4 int); 

Con una produzione come questa:

id scenario p1 p2 p3 p4 
2 1   1 1 1 1 
2 2   1 1 1 1 
2 3   1 1 1 1 

Nota l'uso di rank() invece di row_number() al gruppo stesse combinazioni di (id, scenario) insieme .
Il risultato ha più senso se i conteggi non sono tutti 1.

+0

Hi Erwin, Grazie per aver risposto alla mia domanda! Ho una domanda di follow-up riguardante la funzione crosstab. Risulta che voglio che la mia funzione della tabella a campi incrociati specifichi colonne di valori selezionando ID da un'altra tabella (il secondo parametro della mia tabella incrociata sarebbe "SELECT id_prod FROM prod;"). Come potrei modificare la fine della mia query (dopo AS (rn int, ...)) per mostrare correttamente i risultati di questa modifica? –

Problemi correlati