使用 intarray 对数组元素进行分组和计数

tim*_*one 6 postgresql aggregate array

我正在处理启用了intarray扩展的 Postgres 9.4项目。我们有一个看起来像这样的表:

items
-------------------------------------
id    name                  tag_ids  
--------------------------------------
1     a car                 {1,4}
2     a room to rent        {1}
3     a boat                {1,2,4,11}
4     a wine                {2}
5     emily                 {3}
Run Code Online (Sandbox Code Playgroud)

如果可能,我想对标签 ID 进行分组。就像获取具有tag_id“{1,2,4,11}”的所有元素的计数

tag_id  count
1       3
2       2
4       2
11      1
Run Code Online (Sandbox Code Playgroud)

这可能吗?我会认为这样的交叉点:

select * from items where tag_ids && '{1,2,4,11}'
Run Code Online (Sandbox Code Playgroud)

但我需要按交集结果的数组元素进行分组。如果我按 tag_ids 分组,它只是唯一值。

我该怎么做?

Erw*_*ter 6

保留您已经必须使用索引廉价识别具有任何相关数组元素的行的基本查询。

然后tag_ids & '{1,2,4,11}'LATERAL连接中仅取消嵌套交集 ( ) 。最后,汇总:

SELECT tag_id, count(*) AS ct
FROM   items i
     , unnest(tag_ids & '{1,2,4,11}'::int[]) tag_id
WHERE  tag_ids && '{1,2,4,11}'::int[]
GROUP  BY tag_id
ORDER  BY count(*) DESC;
Run Code Online (Sandbox Code Playgroud)

再一次,intarray 模块交集运算符&是有用的。

之前的相关回答:

不带阵列

如果您还没有intarray安装,或者对于任何其他数组类型,我们需要另一个连接:

SELECT tag_id, count(*) AS ct
FROM  (
   SELECT *
   FROM   items
   WHERE  tag_ids && '{1,2,4,11}'::int[]
   ) i, unnest(tag_ids) t(tag_id)
JOIN unnest('{1,2,4,11}'::int[]) x(tag_id) USING (tag_id)
GROUP BY tag_id
ORDER BY count(*) DESC;
Run Code Online (Sandbox Code Playgroud)

细微的区别:交集运算符折叠重复项以生成不同的元素,而此查询不会。仅当可以有重复的数组元素时才重要......

SQL Fiddle 演示了 和 一个额外的行,该行混合了匹配和不匹配的元素,以证明需要交集或附加连接来消除不需要的元素。