2010-09-30 11 views
11

Mam taką tabelę, aby zapisać wyniki kontroli lekarskiej i datę wysłania raportu i wynik. W rzeczywistości data wysłana jest oparta na dacie przychodni. Klient może mieć jeden lub więcej raportów (data może się różnić)PostgreSQL: jak połączyć wiele wierszy?

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

Chcę wyodrębnić następujący raport z powyższych danych.

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

Pracuję na Postgresql. funkcja "tabeli krzyżowej" nie będzie tutaj działać, ponieważ "date_sent" nie jest spójne dla każdego klienta.

Czy ktoś może podać dokładny pomysł, w jaki sposób należy go sprawdzić?

Odpowiedz

14

Proponuję następujące podejście:

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

nie jest to dokładnie ten sam format wyjściowy, ale to daje te same informacje znacznie szybciej i czystsze.

Jeśli chcesz wyniki w oddzielnych kolumnach, zawsze można to zrobić:

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; 

chociaż będzie oczywiście wprowadzić szereg sztywno możliwych wyników.

+0

Twoje rozwiązanie działa, ale uważam, że OP chce danych w formie tabelowej, jak w pytaniu, tak, że łatwo jest zobacz, gdzie są puste wpisy (klient 1 nie ma na przykład wyniku E). – SabreWolfy

+2

@SabreWolfy: zaktualizowano –

+3

Ta odpowiedź rozwiązuje problem i powinna być zaakceptowana przez PO. – SabreWolfy

0

Podczas gdy czytałem o "symulacji wiersza numer", próbowałem znaleźć inny sposób, aby to zrobić.

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; 

ale zapytanie trwało 10 minut (500 000 ms ++). za 30 000 rekordów. Jest to zbyt długo ..

+0

Użyj opcji WYJAŚNIJ ANALIZĘ, aby zobaczyć, jak wykonywane jest zapytanie i jakie indeksy są używane. client_id potrzebuje indeksu. –

+0

Dzięki Frank .. Zindeksowałem "client_id", a teraz działa w mniej niż 5000 ms. – thinzar00

+2

W Postgres nie trzeba "symulować" numeru wiersza. Ta funkcja jest dostępna od 8,4 (i jeśli korzystasz z wcześniejszej wersji, zdecydowanie zaleca się aktualizację tak szybko, jak to możliwe) –

Powiązane problemy