2

我需要编写一个查询(或函数),它将使用存储hstore在另一个表的列中的值更新表中的现有记录。例如:

create temp table foo(id int primary key, f1 int, f2 text, f3 int);
insert into foo values
  (1, 1, 'jack', 1),
  (2, 2, 'ted' , 2),
  (3, 3, 'fred', 3);

create temp table bar(foo_id int references foo(id), row_data hstore);
insert into bar values
  (1, 'f1=>0, f2=>bill'::hstore),
  (2, 'f1=>0, f2=>will, f3=>0'::hstore),
  (3, 'f3=>0'::hstore);

只有列中具有值的hstore列才会更新,因此在处理之后,所需的结果将是:

select * from foo;
+----+----+------+----+
| id | f1 |  f2  | f3 |
+----+----+------+----+
|  1 |  0 | bill |  1 |
|  2 |  0 | will |  0 |
|  3 |  3 | fred |  0 |
+----+----+------+----+

foo用 中的值更新的“最佳”方法是bar什么?

注意:我将best定义为最容易编码。虽然性能总是很重要,但这是一个批处理作业,速度并不像用户等待结果那样重要。

我正在使用 PostgreSQL 9.4。

4

2 回答 2

3

如果列中未提供任何内容,则保留原始列值hstore...

简单的方法COALESCE

UPDATE foo f
SET    f1 = COALESCE((b.row_data->'f1')::int, f1)
     , f2 = COALESCE( b.row_data->'f2'      , f2)
     , f3 = COALESCE((b.row_data->'f3')::int, f3)
FROM   bar b
WHERE  f.id = b.foo_id
AND    b.row_data ?| '{f1,f2,f3}'::text[];
  • 添加的最后一行立即排除未受影响的行UPDATE?|操作员检查(根据文档):

是否hstore包含任何指定的键?

如果不是这种情况,最便宜的是根本不碰行。
否则,至少有一个(但不一定是全部!)列会收到UPDATE. 这就是COALESCE进来的地方。

但是,根据文档:

值(但不是键)可以是 SQL NULL

所以COALESCE无法区分NULL这里的两种可能含义:

  • 未找到密钥“f2”。
  • b.row_data->'f2'NULL作为 的新值返回f2

也适用于 NULL 值

UPDATE foo f
SET    f1 = CASE WHEN b.row_data ? 'f1'
                 THEN (b.row_data->'f1')::int ELSE f1 END
     , f2 = CASE WHEN b.row_data ? 'f2'
                 THEN b.row_data->'f2'        ELSE f2 END
     , f3 = CASE WHEN b.row_data ? 'f3'
                 THEN (b.row_data->'f3')::int ELSE f3 END
FROM   bar b
WHERE  f.id = b.foo_id
AND    b.row_data ?| '{f1,f2,f3}'::text[];

?操作员检查单个键:

是否hstore包含密钥?

于 2015-04-09T23:38:01.447 回答
0

所以你是在简单的更新之后?作为f1f3是整数,您需要转换它们。否则它只是:

UPDATE foo SET f1 = (row_data->'f1')::integer,
    f2 = row_data->'f2',
    f3 = (row_data->'f3')::integer
    FROM bar WHERE foo.id = foo_id;
于 2015-04-09T18:59:41.070 回答