2013-10-25 8 views
6

Ich bin mit Teradata, ich habe eine Tabelle wie dieseSQL verketten mehrere Zeilen

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

ich die Tabelle abfragen möchten, damit ich

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

Ich versuchte Partition, aber es kann viele sein Namen. Wie bekomme ich dieses Ergebnis? Sogar, um mich in die richtige Richtung zu zeigen, wäre großartig.

Antwort

8

Leider gibt es kein PIVOT in Teradata (nur ein TD_UNPIVOT in 14.10).

Wenn Sie Glück haben, gibt es eine aggregierte UDF auf Ihrer Seite, um eine Gruppen-Concat zu machen (wahrscheinlich geringe Wahrscheinlichkeit).

Andernfalls gibt es zwei Optionen: Rekursion oder Aggregation.

Wenn die maximale Anzahl von Zeilen pro ID bekannt ist, ist die Aggregation normalerweise schneller. Es ist eine Menge Code, aber das meiste davon basiert auf Schnitt & Paste.

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; 

Bei großen Tabellen ist es viel effizienter, wenn Sie das Ergebnis der abgeleitete Tabelle in einer flüchtigen Tabelle materialisieren zunächst die GROUP BY-Spalte als PI verwenden.

Für die Rekursion sollten Sie auch eine flüchtige Tabelle verwenden, da OLAP-Funktionen im rekursiven Teil nicht erlaubt sind. Wenn Sie stattdessen eine Ansicht verwenden, wird die OLAP-Funktion wiederholt berechnet, was zu einer schlechten Leistung führt.

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; 

ist es ein Problem mit diesem Ansatz, könnte es eine Menge Spule benötigen, die leicht zu sehen, wenn Sie die WHERE rn = 1 weglassen.

+0

Vielen Dank für die Weiterleitung an mich –

+0

Das hat mir sehr geholfen, danke. –