【问题标题】:Union of arrays as aggregate function数组联合作为聚合函数
【发布时间】:2017-10-18 07:15:21
【问题描述】:

我有以下输入:

name  | count | options
-----------------------
user1 | 3     | ['option1', 'option2']
user1 | 12    | ['option2', 'option3']
user2 | 2     | ['option1', 'option3']
user2 | 1     | []

我想要以下输出:

name  | count | options
-----------------------
user1 | 12    | ['option1', 'option2', 'option3']
user2 | 2     | ['option1', 'option3']

我按名称分组。对于每个组,计数应汇总为max,选项应汇总为union。我很难弄清楚后者是怎么做的。

目前,我有这个查询:

with data(name, count, options) as (
    select 'user1', 12, array['option1', 'option2']::text[]
    union all
    select 'user1', 12, array['option2', 'option3']::text[]
    union all
    select 'user2', 2, array['option1', 'option3']::text[]
    union all
    select 'user2', 1, array[]::text[]
)
select name, max(count)
from data
group by name

http://rextester.com/YTZ45626

我知道这可以通过定义自定义聚合函数轻松完成,但我想通过查询来完成。我了解unnest() 数组的基础知识(以及array_agg() 稍后的结果),但不知道如何在我的查询中注入它。

【问题讨论】:

  • array_agg() 开头。这能解决你的问题吗?

标签: sql arrays postgresql aggregate-functions


【解决方案1】:

如果你不能做 unnest(例如,因为你需要对其他列求和),这是一个经过简单测试的聚合函数,它连接每个单独的数组:

CREATE OR REPLACE FUNCTION concat_array_agg_sfunc(state ANYARRAY, v ANYARRAY)
  RETURNS ANYARRAY AS
$$
SELECT array_cat(state, v);
$$ LANGUAGE SQL IMMUTABLE;

DROP AGGREGATE IF EXISTS concat_array_agg( ANYARRAY );

CREATE AGGREGATE concat_array_agg( ANYARRAY ) (
  SFUNC = concat_array_agg_sfunc,
  STYPE = ANYARRAY
  );
SELECT
  k,
  concat_array_agg(v)
FROM (VALUES ('a', ARRAY [1,2,3]),
             ('a', ARRAY [4,5,6]),
             ('b', ARRAY [1,2,3]),
             ('b', ARRAY [2,3,4]),
             ('c', ARRAY [2,3,4]),
             ('c', NULL)) t(k, v)
GROUP BY k

【讨论】:

    【解决方案2】:

    您可以在FROM 列表中使用unnest(options) 使用隐式横向连接,然后使用array_agg(distinct v) 创建一个带有选项的数组:

    with data(name, count, options) as (
        select 'user1', 12, array['option1', 'option2']::text[]
        union all
        select 'user1', 12, array['option2', 'option3']::text[]
        union all
        select 'user2', 2, array['option1', 'option3']::text[]
        union all
        select 'user2', 1, array[]::text[]
    )
    select name, array_agg(distinct v)  -- the 'v' here refers to the 'f(v)' alias below
    from data, unnest(options) f(v)
    group by name;
    ┌───────┬───────────────────────────┐
    │ name  │         array_agg         │
    ├───────┼───────────────────────────┤
    │ user1 │ {option1,option2,option3} │
    │ user2 │ {option1,option3}         │
    └───────┴───────────────────────────┘
    (2 rows)
    

    【讨论】:

    • 非常感谢。我不知道如何通过别名引用unnsteded 数组。
    • 当你有多个数组而不是一个数组时,我现在正在尝试一种变体。如果需要,我会努力提出问题!
    猜你喜欢
    • 2020-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-08
    • 2012-07-01
    • 2016-06-27
    • 2021-04-07
    相关资源
    最近更新 更多