Найти наиболее распространенные элементы в массиве с группой по
У меня есть таблица строк со следующей структурой name TEXT, favorite_colors TEXT[], group_name INTEGER
где в каждой строке есть список всех любимых цветов и группы, к которой принадлежит этот человек. Как я могу GROUP BY group_name
и вернуть список наиболее распространенных цветов в каждой группе?
Не могли бы вы сделать комбинацию int[] && int[]
установить для перекрытия, int[] & int[]
чтобы получить пересечение, а затем что-то еще, чтобы сосчитать и оценить?
1 ответ
Быстро и грязно:
SELECT group_name, color, count(*) AS ct
FROM (
SELECT group_name, unnest(favorite_colors) AS color
FROM tbl
) sub
GROUP BY 1,2
ORDER BY 1,3 DESC;
Лучше с LATERAL JOIN
В Postgres 9.3 или новее это более чистая форма:
SELECT group_name, color, count(*) AS ct
FROM tbl t, unnest(t.favorite_colors) AS color
GROUP BY 1,2
ORDER BY 1,3 DESC;
Вышесказанное является сокращением для
...
FROM tbl t
JOIN LATERAL unnest(t.favorite_colors) AS color ON TRUE
...
И как с любым другим INNER JOIN
, это исключило бы строки без цвета (favorite_colors IS NULL
) - как и первый запрос.
Чтобы включить такие строки в результат, используйте вместо этого:
SELECT group_name, color, count(*) AS ct
FROM tbl t
LEFT JOIN LATERAL unnest(t.favorite_colors) AS color ON TRUE
GROUP BY 1,2
ORDER BY 1,3 DESC;
На следующем шаге вы можете легко объединить "наиболее распространенные" цвета для каждой группы, но сначала вам нужно будет определить "наиболее распространенные цвета"...
Самые распространенные цвета
Согласно комментарию, выберите цвета с> 3 вхождений.
SELECT t.group_name, color, count(*) AS ct
FROM tbl t, unnest(t.favorite_colors) AS color
GROUP BY 1,2
HAVING count(*) > 3
ORDER BY 1,3 DESC;
Чтобы объединить верхние цвета в массиве (в порядке убывания):
SELECT group_name, array_agg(color) AS top_colors
FROM (
SELECT group_name, color
FROM tbl t, unnest(t.favorite_colors) AS color
GROUP BY 1,2
HAVING count(*) > 3
ORDER BY 1, count(*) DESC
) sub
GROUP BY 1;
-> SQLfiddle демонстрирует все.