2013-10-25 14 views
6

sto usando Teradata, ho una tabella come questaSQL concatenare più file

ID  String 
123  Jim 
123  John 
123  Jane 
321  Jill 
321  Janine 
321  Johan 

voglio interrogare la tabella in modo da ottenere

ID  String 
123  Jim, John, Jane 
321  Jill, Janine, Johan 

ho provato partizione, ma ci possono essere molti nomi. Come ottengo questo risultato. Anche, indicarmi la giusta direzione sarebbe fantastico.

risposta

8

Sfortunatamente non c'è PIVOT in Teradata (solo un TD_UNPIVOT in 14.10).

Se hai fortuna c'è un UDF aggregato nel tuo sito per fare un concat di gruppo (probabilmente bassa possibilità).

Altrimenti ci sono due opzioni: ricorsione o aggregazione.

Se il numero massimo di righe per ID è noto, l'aggregazione è normalmente più veloce. È un sacco di codice, ma la maggior parte si basa sul taglio & incolla.

SELECT 
    id, 
    MAX(CASE WHEN rn = 1 THEN string END) 
    || MAX(CASE WHEN rn = 2 THEN ',' || string ELSE '' END) 
    || MAX(CASE WHEN rn = 3 THEN ',' || string ELSE '' END) 
    || MAX(CASE WHEN rn = 4 THEN ',' || string ELSE '' END) 
    || ... -- repeat up to the known maximum 
FROM 
(
    SELECT 
     id, string, 
     ROW_NUMBER() 
     OVER (PARTITION BY id 
      ORDER BY string) AS rn 
    FROM t 
) AS dt 
GROUP BY 1; 

Per tabelle di grandi dimensioni è molto più efficiente quando si materializzare il risultato della tabella derivata in una tabella volatile prima utilizzando GROUP BY colonna come PI.

Per la ricorsione è necessario utilizzare anche una tabella volatile, poiché le funzioni OLAP non sono consentite nella parte ricorsiva. L'utilizzo di una vista, invece, calcola ripetutamente la funzione OLAP e quindi porta a prestazioni non buone.

CREATE VOLATILE TABLE vt AS 
(
    SELECT 
     id 
     ,string 
     ,ROW_NUMBER() 
     OVER (PARTITION BY id 
      ORDER BY string DESC) AS rn -- reverse order! 
     ,COUNT(*) 
     OVER (PARTITION BY id) AS cnt 
    FROM t 
) WITH DATA 
UNIQUE PRIMARY INDEX(id, rn) 
ON COMMIT PRESERVE ROWS; 

WITH RECURSIVE cte 
(id, list, rn) AS 
(
    SELECT 
     id 
     ,CAST(string AS VARCHAR(1000)) -- define maximum size based on maximum number of rows 
     ,rn 
    FROM vt 
    WHERE rn = cnt 

    UNION ALL 

    SELECT 
     vt.id 
     ,cte.list || ',' || vt.string 
     ,vt.rn 
    FROM vt 
    JOIN cte 
    ON vt.id = cte.id 
    AND vt.rn = cte.rn - 1 
) 
SELECT id, list 
FROM cte 
WHERE rn = 1; 

C'è un problema con questo approccio, si potrebbe aver bisogno di un sacco di rocchetto che è facile da vedere quando si omette il WHERE rn = 1.

+0

Grazie per il reindirizzamento –

+0

Questo mi ha aiutato moltissimo, grazie. –

Problemi correlati