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 - 将两列聚合为一项的主要内容,如果未能解决你的问题,请参考以下文章