Postgres - 将两列聚合为一项

Posted

技术标签:

【中文标题】Postgres - 将两列聚合为一项【英文标题】:Postgres - aggregate two columns into one item 【发布时间】:2016-03-13 19:19:34 【问题描述】:

我想在分组时将两列聚合成一个“数组”。

假设一个像这样的表:

friends_map:
=================================
user_id    friend_id    confirmed
=================================
1          2            true
1          3            false
2          1            true
2          3            true
1          4            false

我想从这个表中选择并按 user_id 分组并获取friend_id 并确认为用逗号分隔的连接值。

目前我有这个:

SELECT user_id, array_agg(friend_id) as friends, array_agg(confirmed) as confirmed
FROM friend_map
WHERE user_id = 1
GROUP BY user_id

这让我很感动:

=================================
user_id    friends      confirmed
=================================
1         [2,3,4]       [t, f, f]

如何获得:

=================================
user_id    friends     
=================================
1         [ [2,t], [3,f], [4,f] ]

【问题讨论】:

从某种意义上说,这就是你刚开始时所拥有的。 :) 但我正在寻找的是分组在一个变量名下。这只是一个示例,它实际上是更大的连接查询的一部分,其中包含更多的表和数据。 【参考方案1】:

您可以在将值输入array_agg() 函数之前将它们连接在一起:

SELECT user_id, array_agg('[' || friend_id || ',' || confirmed || ']') as friends
FROM friends_map
WHERE user_id = 1
GROUP BY user_id

演示:SQL Fiddle

【讨论】:

请注意,这是在构建像 '[2,t]' 这样的字符串,而不是嵌套数组。实际的 Postgres 数组不能包含不同类型的值(如整数和布尔值)。 @DanielLyons 好点,我不习惯考虑将这样的嵌套数组存储在 rdbms 中,所以考虑字符串。 没关系;做错事没有正确的方法。 :) 谢谢,这可能会做得很好,最终结果是 javascript,它可以在数组中有不同的类型。我这样做的另一种方法是将confirmed的类型转换为int(0和1)以表示false和true,那么类型将是相同的。【参考方案2】:

Postgres 9.5 中,您可以获得文本数组数组:

SELECT user_id, array_agg(array[friend_id::text, confirmed::text])
FROM friend_map
WHERE user_id = 1
GROUP BY user_id;

 user_id |           array_agg            
---------+--------------------------------
       1 | 2,true,3,false,4,false
(1 row)

或 int 数组的数组:

SELECT user_id, array_agg(array[friend_id, confirmed::int])
FROM friend_map
WHERE user_id = 1
GROUP BY user_id;

 user_id |      array_agg      
---------+---------------------
       1 | 2,1,3,0,4,0
(1 row) 

【讨论】:

问个问题,你用的是什么版本? array_agg 不应该聚合 text[]integer[]... 操作! PostgreSQL 9.5beta2 啊哈!你让我到了那里,我想知道那是什么样的 巫术 :) 9.5 还没有发布,所以我认为 OP 正在寻找一些生产就绪的解决方案。【参考方案3】:
SELECT user_id, array_agg((friend_id, confirmed)) as friends
FROM friend_map
WHERE user_id = 1
GROUP BY user_id

user_id |           array_agg            
--------+--------------------------------
      1 | "(2,true)","(3,false)","(4,false)"

【讨论】:

【参考方案4】:

你可以避免多维数组的丑陋,并使用一些支持混合数据类型的json:

SELECT user_id, json_agg(json_build_array(friend_id, confirmed)) AS friends 
    FROM friends_map 
    WHERE user_id = 1
    GROUP BY user_id

或者使用一些 key : value 对,因为 json 允许这样做,所以如果你愿意,你的输出会更语义

SELECT user_id, json_agg(json_build_object(
        'friend_id', friend_id, 
        'confirmed', confirmed
    )) AS friends 
    FROM friends_map 
    WHERE user_id = 1
    GROUP BY user_id;

【讨论】:

这绝对是正确的答案,你会得到很好的结果作为 json (这可能是我们都想要的),它看起来像 [[1990,"pm25"],[1995,"pm25 "],[2000,"pm25"]] 这绝对是美丽的——正如@chrismarx 所说,这正是我想要的最终结果。 (我假设我必须在查询后在 postgres 之外处理) 这是正确的答案;这里的目标是创建一个嵌套数组,而这正是这样做的。正如其他对话所反映的,不允许嵌套不同类型的数组。【参考方案5】:

您可以使用:array[]

就这样做吧:

SELECT user_id, array[friend_id, confirmed]
FROM friend_map
WHERE user_id = 1
GROUP BY 1;

【讨论】:

以上是关于Postgres - 将两列聚合为一项的主要内容,如果未能解决你的问题,请参考以下文章

Java GridLayout 如何将两列合并为一列?

SQL select 将两列合二为一

如何像蜂巢中的地图一样将两列合并为一列?

两列中的Postgres不同查询

在 Postgres 中将多列合并为一列

Postgres 聚合