2010-09-30 17 views
11

Ich habe eine Tabelle wie diese, um die Ergebnisse einer medizinischen Untersuchung und das Datum des Berichts gesendet und das Ergebnis zu speichern. Tatsächlich basiert das gesendete Datum auf dem clinic_visit-Datum. Ein Client kann einen oder mehrere Berichte haben (Datum Mai variiert)PostgreSQL: Wie kombiniert man mehrere Zeilen?

--------------------------------------- 
| client_id | date_sent | result | 
--------------------------------------- 
| 1   | 2001  | A | 
| 1   | 2002  | B | 
| 2   | 2002  | D | 
| 3   | 2001  | A | 
| 3   | 2003  | C | 
| 3   | 2005  | E | 
| 4   | 2002  | D | 
| 4   | 2004  | E | 
| 5   | 2004  | B | 
--------------------------------------- 

ich den folgenden Bericht aus den obigen Daten extrahieren möchten.

--------------------------------------------------- 
| client_id | result1 | result2 | resut3 | 
--------------------------------------------------- 
|  1  | A  | B  |   | 
|  2  | D  |   |   | 
|  3  | A  | C  |  E  | 
|  4  | D  | E  |   | 
|  5  | B  |   |   | 
--------------------------------------------------- 

Ich arbeite an Postgresql. Die "Kreuztabellen" -Funktion wird hier nicht funktionieren, da "date_sent" nicht für jeden Client konsistent ist.

Kann jemand bitte eine ungefähre Idee geben, wie es abgefragt werden sollte?

Antwort

14

Ich schlage vor, den folgenden Ansatz:

SELECT client_id, array_agg(result) AS results 
    FROM labresults 
    GROUP BY client_id; 

Es ist nicht genau das gleiche Ausgabeformat, aber es wird Ihnen die gleichen Informationen viel schneller und sauberer geben.

Wenn Sie die Ergebnisse in separaten Spalten möchten, können Sie dies immer tun:

SELECT client_id, 
     results[1] AS result1, 
     results[2] AS result2, 
     results[3] AS result3 
FROM 
(
    SELECT client_id, array_agg(result) AS results 
     FROM labresults 
     GROUP BY client_id 
) AS r 
ORDER BY client_id; 

obwohl das offensichtlich eine hartkodierte Anzahl der möglichen Ergebnisse vorstellen.

+0

Ihre Lösung funktioniert, aber ich denke, das OP will die Daten wie in der Frage tabelliert, so dass es einfach ist sehen wo leere Einträge sind (Client 1 hat zB kein Ergebnis E). – SabreWolfy

+2

@SabreWolfy: aktualisiert –

+3

Diese Antwort löst das Problem und sollte vom OP akzeptiert werden. – SabreWolfy

0

Während ich über "Simulation row_number" las, versuchte ich, eine andere Möglichkeit zu finden, dies zu tun.

SELECT client_id, 
     MAX(CASE seq WHEN 1 THEN result ELSE '' END) AS result1, 
     MAX(CASE seq WHEN 2 THEN result ELSE '' END) AS result2, 
     MAX(CASE seq WHEN 3 THEN result ELSE '' END) AS result3, 
     MAX(CASE seq WHEN 4 THEN result ELSE '' END) AS result4, 
     MAX(CASE seq WHEN 5 THEN result ELSE '' END) AS result5 
FROM (SELECT p1.client_id, 
       p1.result, 
       (SELECT COUNT(*) 
       FROM labresults p2 
       WHERE p2.client_id = p1.client_id 
       AND p2.result <= p1.result) 
     FROM labresults p1 
) D (client_id, result, seq) 
GROUP BY client_id; 

aber die Abfrage dauerte 10 Minuten (500.000 ms ++). für 30.000 Datensätze. Dies ist zu lang ..

+0

Verwenden Sie EXPLAIN ANALAYZE, um zu sehen, wie die Abfrage ausgeführt wird und welche Indizes verwendet werden. client_id benötigt einen Index. –

+0

Danke Frank .. Ich indizierte die "client_id" und jetzt läuft es in weniger als 5000ms. – thinzar00

+2

Mit Postgres müssen Sie die row_number nicht "simulieren". Diese Funktion ist seit 8.4 verfügbar (und wenn Sie eine frühere Version verwenden, würde ich dringend empfehlen, so schnell wie möglich zu aktualisieren) –