【问题标题】:Postgres - aggregate two columns into one itemPostgres - 将两列聚合为一项
【发布时间】: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] ]

【问题讨论】:

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

标签: sql arrays postgresql aggregate-functions


【解决方案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;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-23
      相关资源
      最近更新 更多