Группировать по нескольким столбцам и получать результат в виде массива в отдельных столбцах - PullRequest
2 голосов
/ 10 октября 2019

У меня есть таблица, подобная следующей:

| col_A | col_B |
|-------|-------|
| 1     | 1     |
| 1     | 2     |
| 1     | 3     |
| 2     | 1     |
| 2     | 2     |
| 2     | 3     |
| 3     | 1     |
| 3     | 2     |

Я хочу сгруппировать и объединить результаты в массив, как показано ниже:

| col_A | col_B |
|-------|-------|
| 1,2   | 1,2,3 |
| 3     |  1,2  |

Моя попытка написать запрос:

SELECT col_A, array_agg(col_B ORDER BY col_B DESC) FROM table GROUP BY col_A;

Однако, это выводит:

| col_A | col_B   |
|-------|---------|
| 1     | {1,2,3} |
| 2     | {1,2,3} |
| 3     | {1,2}   |

Ответы [ 2 ]

1 голос
/ 10 октября 2019

В Postgres упорядочение строк в подзапросе обычно дешевле, чем добавление предложения ORDER BY к статистической функции:

SELECT array_agg(col_a) AS col_a, col_b
FROM  (
   SELECT col_a, array_agg(col_b) AS col_b
   FROM  (TABLE tbl ORDER BY col_a, col_b) t
   GROUP  BY 1
   ORDER  BY 1
   ) sub
GROUP  BY 2
ORDER  BY 1;

Точно создает желаемый результат, включая порядок элементов и строк.

db <> fiddle здесь

Первый ORDER BY предназначен для сортировки элементов перед построением массива в col_b.
ВторойORDER BY - сортировка элементов перед построением массива в col_a.
3-й ORDER BY - вывод строк в порядке, предложенном результатом примера OP.

Запрос должен работают одинаково без 2-го и 3-го ORDER BY, потому что 1-й ордер переносится. Но нет никаких гарантий. (Такие вещи, как параллелизм, могут испортить порядок при запросе больших таблиц.) Представленный запрос гарантирован для получения желаемого порядка.

Похожие:

О позиционных ссылках в GROUP BY и ORDER BY:

О (TABLE tbl ORDER BY col_a, col_b):

1 голос
/ 10 октября 2019

Похоже, что вы хотите агрегировать col_b, сгруппированные по col_a, а затем агрегировать col_a, сгруппированные по агрегированным массивам. Вы можете сделать это с помощью вложенного запроса, первый шаг которого вы уже сделали:

SELECT array_agg(col_a), col_b
FROM (SELECT col_a, array_agg(DISTINCT col_b ORDER BY col_b) AS col_b
      FROM example GROUP BY col_a) grouped_b
GROUP BY col_b;

( online demo )

...