我需要编写一个查询(或函数),它将使用存储在另一个表的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。
答案 0 :(得分: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
排除未受影响的行: ?|
运算符检查(per documentation):
hstore
是否包含任何指定的密钥?
如果情况并非如此,那么最便宜的是不要触摸该行。
否则,列中至少有一列(但不一定是全部!)会收到UPDATE
。 COALESCE
进来的地方。
值(但不是键)可以是SQL
NULL
。
所以COALESCE
无法区分NULL
的两种可能含义:
b.row_data->'f2'
返回NULL
作为f2
的新值。
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[];
?
operator检查单个密钥:
hstore
是否包含密钥?
答案 1 :(得分:0)
所以你经过一次简单的更新?由于f1
和f3
是整数,因此您需要投射这些整数。否则就是:
UPDATE foo SET f1 = (row_data->'f1')::integer,
f2 = row_data->'f2',
f3 = (row_data->'f3')::integer
FROM bar WHERE foo.id = foo_id;