2017-03-21 43 views
1

我有數據,像這樣的hstore:總結hstore BY

|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 

但是這給:

ERROR: subquery uses ungrouped column "my_table.views" from outer query

任何幫助表示讚賞!

回答

4

這是因爲在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; 
+0

真是太爽了@Abelisto。非常感激。 –

1

如果您創建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;