想象一下,我有一个包含这个定义的表:
CREATE TABLE test (
values HSTORE NOT NULL
);
想象一下,我插入了一些记录,最后得到以下内容:
values
-----------------------------
"a"=>"string1","b"=>"string2"
"b"=>"string2","c"=>"string3"
有没有什么方法可以创建一个聚合查询,它将为我提供一个新的hstore,其中包含所有行的合并键(和值)。
伪查询:
SELECT hstore_sum(values) AS value_sum FROM test;
期望的结果:
value_sum
--------------------------------------------
"a"=>"string1","b"=>"string2","c"=>"string3"
我知道每个键的不同值存在潜在冲突,但在我的情况下,选择值的顺序/优先级并不重要(它甚至不必是确定性的,因为它们对于相同的关键)。
这是开箱即用的,还是必须使用某些特定的自制SQL函数来完成它?
答案 0 :(得分:4)
你可以做很多事情,f.ex:
我的第一个想法是使用each()
函数,并分别聚合键和值,如:
SELECT hstore(array_agg(key), array_agg(value))
FROM test,
LATERAL each(hs);
但这表现最差。
您也可以使用hstore_to_array()
函数来构建键值更改数组,如(@JakubKania):
SELECT hstore(array_agg(altering_pairs))
FROM test,
LATERAL unnest(hstore_to_array(hs)) altering_pairs;
但这还不完美。
您可以依赖hstore
值'表示,并构建一个包含所有对的字符串:
SELECT hstore(string_agg(nullif(hs::text, ''), ','))
FROM test;
这很快。但是,如果需要,可以使用custom aggregate function(可以使用内置的hstore
连接):
CREATE AGGREGATE hstore_sum (hstore) (
SFUNC = hs_concat(hstore, hstore),
STYPE = hstore
);
-- i used the internal function (hs_concat) for the concat (||) operator,
-- if you do not want to rely on this function,
-- you could easily write an equivalent in a custom SQL function
SELECT hstore_sum(hs)
FROM test;
答案 1 :(得分:0)
在内置功能中没有,但是hstore提供了一些允许将其转换为其他内容的函数,例如数组。所以我们将它转换为数组,合并数组并从最终数组创建hstore:
SELECT hstore(array_agg(x)) FROM
(SELECT unnest(hstore_to_array(hs)) AS x
FROM test)
as q;
http://sqlfiddle.com/#!15/cb11a/1
P.S。其他一些组合(比如使用JSON)可能更有效。
答案 2 :(得分:0)
这就是我现在在生产中使用的内容。我避免类型之间过度转换,例如hstore
和array
。我也不能直接使用hs_concat
作为sfunc
,因为如果汇总的任何哈希值为NULL
,它将生成NULL
。
CREATE OR REPLACE FUNCTION public.agg_hstore_sum_sfunc(state hstore, val hstore)
RETURNS hstore AS $$
BEGIN
IF val IS NOT NULL THEN
IF state IS NULL THEN
state := val;
ELSE
state := state || val;
END IF;
END IF;
RETURN state;
END;
$$ LANGUAGE 'plpgsql';
CREATE AGGREGATE public.sum(hstore) (
SFUNC = public.agg_hstore_sum_sfunc,
STYPE = hstore
);