Объединить несколько строк в массиве с SQL на PostgreSQL
У меня есть таблица, построенная так:
oid | identifier | value
1 | 10 | 101
2 | 10 | 102
3 | 20 | 201
4 | 20 | 202
5 | 20 | 203
Я хотел бы запросить эту таблицу, чтобы получить такой результат:
identifier | values[]
10 | {101, 102}
20 | {201, 202, 203}
Я не могу придумать, как это сделать. Это возможно? Как?
Большое спасибо.
4 ответа
Это встроенный в Postgres, так как несколько версий, поэтому вам больше не нужно определять свою собственную, имя array_agg()
,
test=> select array_agg(n) from generate_series(1,10) n group by n%2;
array_agg
--------------
{1,3,5,7,9}
{2,4,6,8,10}
(это Postgres 8.4.8).
Обратите внимание, что нет ORDER BY
указан, поэтому порядок строк результата зависит от используемого метода группировки (здесь хэш), т. е. он не определен. Пример:
test=> select n%2, array_agg(n) from generate_series(1,10) n group by (n%2);
?column? | array_agg
----------+--------------
1 | {1,3,5,7,9}
0 | {2,4,6,8,10}
test=> select (n%2)::TEXT, array_agg(n) from generate_series(1,10) n group by (n%2)::TEXT;
text | array_agg
------+--------------
0 | {2,4,6,8,10}
1 | {1,3,5,7,9}
Теперь я не знаю, почему вы получаете {10,2,4,6,8}
а также {9,7,3,1,5}
, поскольку generate_series()
следует отправить строки по порядку.
Простой пример: у каждого курса много уроков, поэтому, если я запускаю код ниже:
SELECT
lessons.course_id AS course_id,
array_agg(lessons.id) AS lesson_ids
FROM lessons
GROUP BY
lessons.course_id
ORDER BY
lessons.course_id
я бы получил следующий результат:
┌───────────┬──────────────────────────────────────────────────────┐
│ course_id │ lesson_ids │
├───────────┼──────────────────────────────────────────────────────┤
│ 1 │ {139,140,141,137,138,143,145,174,175,176,177,147,... │
│ 3 │ {32,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,... │
│ 5 │ {663,664,665,649,650,651,652,653,654,655,656,657,... │
│ 7 │ {985,984,1097,974,893,971,955,960,983,1045,891,97... │
│ ... │
└───────────┴──────────────────────────────────────────────────────┘
Вы должны создать агрегатную функцию, например
CREATE AGGREGATE array_accum (anyelement)
(
sfunc = array_append,
stype = anyarray,
initcond = '{}'
);
затем
SELECT identifier, array_accum(value) AS values FROM table GROUP BY identifier;
НТН
Вот код для запрошенного вывода.
select identifier, array_agg(value)
from (
values
(1 , 10 , 101),
(2 , 10 , 102),
(3 , 20 , 201),
(4 , 20 , 202),
(5 , 20 , 203)
) as tab (oid, identifier, value)
group by identifier
order by identifier;