2010-09-30 11 views
11

Tengo una tabla como esta para guardar los resultados de un chequeo médico y la fecha del informe enviado y el resultado. En realidad, la fecha de envío se basa en la fecha de clinic_visit. Un cliente puede tener uno o más informes (la fecha puede variar)PostgreSQL: cómo combinar múltiples filas?

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

Deseo extraer el siguiente informe de los datos anteriores.

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

Estoy trabajando en Postgresql. la función "tabla cruzada" no funcionará aquí porque "date_sent" no es consistente para cada cliente.

¿Alguien puede dar una idea aproximada de cómo se debe consultar?

Respuesta

14

que sugieren el siguiente enfoque:

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

no es exactamente el mismo formato de salida, pero le dará la misma información mucho más rápido y más limpio.

Si desea que los resultados en columnas separadas, siempre se puede hacer esto:

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; 

a pesar de que, obviamente, introducir un número codificado de posibles resultados.

+0

Su solución funciona, pero creo que el OP desea que los datos se tabulen como en la pregunta, de modo que sea fácil ver dónde están las entradas vacías (el cliente 1 no tiene el resultado E, por ejemplo). – SabreWolfy

+2

@SabreWolfy: actualizado –

+3

Esta respuesta resuelve el problema y debe ser aceptado por el OP. – SabreWolfy

0

Mientras estaba leyendo sobre "simular row_number", traté de encontrar otra forma de hacerlo.

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; 

pero la consulta tomó 10 minutos (500,000 ms ++). para 30,000 registros. Esto es demasiado largo ..

+0

Use EXPLAIN ANALAYZE para ver cómo se ejecuta la consulta y qué índices se utilizan. client_id necesita un índice. –

+0

Gracias Frank ... Indiqué el "client_id" y ahora funciona en menos de 5000ms. – thinzar00

+2

Con Postgres no necesita "simular" row_number. Esa función está disponible desde 8.4 (y si está utilizando una versión anterior, recomiendo actualizar lo antes posible) –

Cuestiones relacionadas