合并多行的hstore数据

时间:2014-09-15 11:20:13

标签: postgresql aggregate hstore

想象一下,我有一个包含这个定义的表:

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函数来完成它?

3 个答案:

答案 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;

SQLFiddle

答案 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)

这就是我现在在生产中使用的内容。我避免类型之间过度转换,例如hstorearray。我也不能直接使用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
);