Вы должны взглянуть на Функции и разделы окна или, возможно, array_agg
.
. Принимая этот пример:
CREATE TABLE mytable (
id SERIAL PRIMARY KEY,
user_id INTEGER,
start INTEGER,
finish INTEGER
);
INSERT INTO mytable(id, user_id, start, finish) VALUES (1, 1, 5, 10); -- duration: 5
INSERT INTO mytable(id, user_id, start, finish) VALUES (2, 2, 10, 30); -- duration: 20
INSERT INTO mytable(id, user_id, start, finish) VALUES (3, 1, 15, 20); -- duration: 5
Как вы знаете, SELECT SUM(finish - start), user_id FROM mytable GROUP BY user_id
будетreturn:
10 | 1
20 | 2
Я предполагаю, что вам не нужен вывод этого запроса (поскольку вы также можете не использовать агрегаты, если вы используете столбец с уникальным ненулевым ограничением в вашем GROUP BY
, как я предполагаю id
is): SELECT id, SUM(finish - start), user_id FROM mytable GROUP BY user_id, id
.
Используя оконную функцию, вы можете использовать данные из других строк, связанных с текущей строкой.
Следующий запрос:
SELECT id, SUM(finish - start) OVER (PARTITION BY user_id) AS duration, user_id
FROM mytable ORDER BY user_id
дает следующие результаты:
1 | 10 | 1
3 | 10 | 1
2 | 20 | 2
Теперь вы получите строку для id
используемого, но SUM
применяется ко всему набору строк в рамке окна(здесь все те, у кого user_id
совпадает с текущей строкой).
Что касается вашего приложения, вам, вероятно, потребуется прочитать строки одну за другой и сохранить соответствующие значения id
где-то, пока user_id
не изменится.
В качестве альтернативы, вы можете использовать array_agg
, чтобы объединить все идентификаторы в массив:
SELECT array_agg(id), SUM(finish - start) AS duration, user_id
FROM mytable GROUP BY user_id ORDER BY user_id, duration
{1, 3} | 10 | 1
{2} | 20 | 2
Если, например, вы хотите это в строке через пробел, используйте array_to_string
поверх этого:
SELECT array_to_string(array_agg(id), ' '), SUM(finish - start) AS duration, user_id
FROM mytable GROUP BY user_id ORDER BY user_id, duration