PostgreSQL: как объединить несколько строк?
У меня есть таблица, подобная этой, чтобы сохранить результаты медицинского осмотра и дату отправки отчета и результат. Фактически дата отправления основана на дате clinic_visit. Клиент может иметь один или несколько отчетов (дата может варьироваться)
---------------------------------------
| 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 |
---------------------------------------
Я хочу извлечь следующий отчет из приведенных выше данных.
---------------------------------------------------
| client_id | result1 | result2 | resut3 |
---------------------------------------------------
| 1 | A | B | |
| 2 | D | | |
| 3 | A | C | E |
| 4 | D | E | |
| 5 | B | | |
---------------------------------------------------
Я работаю над Postgresql. функция "кросс-таблицы" здесь не работает, потому что "date_sent" не соответствует каждому клиенту.
Кто-нибудь может дать приблизительное представление о том, как его следует запрашивать?
Ответы
Ответ 1
Предлагаю следующий подход:
SELECT client_id, array_agg(result) AS results
FROM labresults
GROUP BY client_id;
Это не совсем тот же формат вывода, но он даст вам ту же информацию намного быстрее и чище.
Если вы хотите получить результаты в отдельных столбцах, вы всегда можете сделать это:
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;
хотя это, очевидно, приведет к жесткому количеству возможных результатов.
Ответ 2
Пока я читал о "имитации row_number", я попытался выяснить другой способ сделать это.
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;
но запрос занял 10 минут (500 000 мc++). для 30 000 записей. Это слишком долго.