【问题标题】:Aggregate hstore in Postgres within GROUP BY在 GROUP BY 内的 Postgres 中聚合 hstore
【发布时间】:2017-03-21 21:04:18
【问题描述】:

我有这样的 hstore 数据:

|brand|account|likes|views                 | 
|-----|-------|-----|----------------------|
|Ford |ford_uk|1    |"3"=>"100"            |
|Ford |ford_us|2    |"3"=>"200", "5"=>"10" |
|Jeep |jeep_uk|3    |"3"=>"300"            |
|Jeep |jeep_us|4    |"3"=>"400", "5"=>"20" |

我希望能够按键汇总 hstores,按品牌分组:

|brand|likes|views                 | 
|-----|-----|----------------------|
|Ford |3    |"3"=>"300", "5"=>"10" |
|Jeep |7    |"3"=>"700", "5"=>"20" |

This answer 为如何在没有 GROUP BY 的情况下执行此操作提供了一个很好的解决方案。使其适应这种情况会得到类似的结果:

SELECT
  sum(likes) AS total_likes,
 (SELECT hstore(array_agg(key), array_agg(value::text))
  FROM (
    SELECT s.key, sum(s.value::integer)
    FROM (
      SELECT((each(views)).*)
    ) AS s(key, value)
    GROUP BY key
  ) x(key, value)) AS total_views
FROM my_table
GROUP BY brand

但是这给出了:

错误:子查询使用来自外部查询的未分组列“my_table.views”

任何帮助表示赞赏!

【问题讨论】:

    标签: sql postgresql postgresql-9.5


    【解决方案1】:

    这是因为在group by 查询中使用了没有聚合函数的views 列。
    非常快速的解决方法:

    with my_table(brand,account,likes,views) as (
      values
        ('Ford', 'ford_uk', 1, '"3"=>"100"'::hstore),
        ('Ford', 'ford_uk', 2, '"3"=>"200", "5"=>"10"'),
        ('Jeep', 'jeep_uk', 3, '"3"=>"300"'::hstore),
        ('Jeep', 'jeep_uk', 4, '"3"=>"400", "5"=>"20"'))
    SELECT
      brand,
      sum(likes) AS total_likes,
     (SELECT hstore(array_agg(key), array_agg(value::text))
      FROM (
        SELECT s.key, sum(s.value::integer)
        FROM 
          unnest(array_agg(views)) AS h, --<< aggregate views according to the group by, then unnest it into the table
          each(h) as s(key,value)
        GROUP BY key
      ) x(key, value)) AS total_views
    FROM my_table
    GROUP BY brand
    

    更新

    您也可以为此类任务创建aggregate

    --drop aggregate if exists hstore_sum(hstore);
    --drop function if exists hstore_sum_ffunc(hstore[]);
    create function hstore_sum_ffunc(hstore[]) returns hstore language sql immutable as $$
      select hstore(array_agg(key), array_agg(value::text))
      from
        (select s.key, sum(s.value::numeric) as value
         from unnest($1) as h, each(h) as s(key, value) group by s.key) as t
    $$;
    create aggregate hstore_sum(hstore) 
    (
        SFUNC = array_append,
        STYPE = hstore[],
        FINALFUNC = hstore_sum_ffunc,
        INITCOND = '{}'
    );
    

    之后,您的查询将更简单、更“规范”:

    select
      brand, 
      sum(likes) as total_likes,
      hstore_sum(views) as total_views
    from my_table
    group by brand;
    

    更新 2

    即使没有create aggregate,函数hstore_sum_ffunc 也可能有用:

    select
      brand, 
      sum(likes) as total_likes,
      hstore_sum_ffunc(array_agg(views)) as total_views
    from my_table
    group by brand;
    

    【讨论】:

      【解决方案2】:

      如果您为hstore 创建一个聚合,这会变得容易一些:

      create aggregate hstore_agg(hstore) 
      (
        sfunc = hs_concat(hstore, hstore),
        stype = hstore
      );
      

      那么你可以这样做:

      with totals as (
        select t1.brand,
               hstore(k, sum(v::int)::text) as views
        from my_table t1, each(views) x(k,v)
        group by brand, k
      ) 
      select brand, 
             (select sum(likes) from my_table t2 where t1.brand = t2.brand) as likes, 
             hstore_agg(views) as views
      from totals t1
      group by brand;
      

      另一种选择是将可能很慢的相关子查询移到 CTE 中:

      with vals as (
        select t1.brand,
               hstore(k, sum(v::int)::text) as views
        from my_table t1, each(views) x(k,v)
        group by brand, k
      ), view_totals as (
        select brand, 
               hstore_agg(views) as views
        from vals
        group by brand
      ), like_totals as (
        select brand, 
               sum(likes) as likes
        from my_table
        group by brand
      )
      select vt.brand, 
             lt.likes,
             vt.views
      from view_totals vt
        join like_totals lt on vt.brand = lt.brand
      order by brand;
      

      【讨论】:

        猜你喜欢
        • 2014-10-25
        • 1970-01-01
        • 2014-11-22
        • 2014-12-27
        • 2022-01-06
        • 1970-01-01
        • 2014-08-24
        • 1970-01-01
        • 2016-04-29
        相关资源
        最近更新 更多