使用其他 hstore 值更新 hstore 值

Update hstore values with other hstore values

我有一个摘要 table,它会定期用新数据更新。其中一列是 hstore 类型。当我更新新数据时,如果键存在,我想将键的值添加到键的现有值,否则我想将对添加到 hstore。

现有数据:

id     sum     keyvalue
--------------------------------------
1      2       "key1"=>"1","key2"=>"1"

新数据:

id    sum      keyvalue
--------------------------------------------------
1     3        "key1"=>"1","key2"=>"1","key3"=>"1"

想要的结果:

id    sum      keyvalue
--------------------------------------------------
1     5        "key1"=>"2","key2"=>"2","key3"=>"1"

我想在插入的冲突部分执行此操作。 求和部分很简单。但是我还没有找到如何以这种方式连接 hstore。

没有内置的东西。您必须编写一个函数来接受 hstore 值并以您想要的方式合并它们。

create function merge_and_increment(p_one hstore, p_two hstore)
  returns hstore
as
$$
  select hstore_agg(hstore(k,v))
  from (
    select k, sum(v::int)::text as v
    from (
      select *
      from each(p_one) as t1(k,v)
      union all
      select *
      from each(p_two) as t2(k,v)
    ) x
    group by k
  ) s
$$
language sql;

hstore_agg() 函数也不是内置的,但很容易定义它:

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

所以结果是:

select merge_and_increment(hstore('"key1"=>"1","key2"=>"1"'), hstore('"key1"=>"1","key2"=>"1","key3"=>"1"'))

是:

merge_and_increment                  
-------------------------------------
"key1"=>"2", "key2"=>"2", "key3"=>"1"

请注意,如果存在无法转换为整数的值,该函数将严重失败。

对于插入语句,您可以像这样使用它:

insert into the_table (id, sum, data)
values (....) 
on conflict (id) do update
   set sum = the_table.sum + excluded.sum, 
       data = merge_and_increment(the_table.data, excluded.data);

demo:db<>fiddle

CREATE OR REPLACE FUNCTION sum_hstore(_old hstore, _new hstore) RETURNS hstore
AS $$
DECLARE
    _out hstore;
BEGIN
    SELECT
        hstore(array_agg(key), array_agg(value::text))
    FROM (
        SELECT
            key,
            SUM(value::int) AS value
        FROM (
            SELECT * FROM each('"key1"=>"1","key2"=>"1"'::hstore)

            UNION ALL

            SELECT * FROM each('"key1"=>"1","key2"=>"1","key3"=>"1"')
        ) s
        GROUP BY key
    ) s
    INTO _out;

    RETURN _out;
END;
$$
LANGUAGE plpgsql;
  1. each() 将 key/value 对扩展为每对一行,其中包含列键和值
  2. 将类型 text 转换为类型 int 和 group/sum values
  3. 使用 hstore(array, array) 函数聚合成一个新的 hstore 值。数组元素是 key 列的值和 value 列的值。

你可以做这样的更新:

UPDATE mytable
SET keyvalue = sum_hstore(keyvalue, '"key1"=>"1","key2"=>"1","key3"=>"1"')
WHERE id = 1;