从另一个 table 中的 hstore 列更新现有行
UPDATE existing rows from hstore column in another table
我需要编写一个查询(或函数),用存储在另一个 table 的 hstore
列中的值更新 table 中的现有记录。例如:
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 |
+----+----+------+----+
用 bar
中的值更新 foo
的 "best" 方法是什么?
注意:我将 最佳 定义为最容易编写代码。虽然性能始终很重要,但这是一个批处理作业,速度并不像用户等待结果时那样重要。
我正在使用 PostgreSQL 9.4。
所以您是在进行简单的更新?由于 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;
如果 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):
does hstore
contain any of the specified keys?
如果不是这种情况,则根本不触摸该行是最便宜的。
否则,至少有一个(但不一定是所有!)列收到 UPDATE
。这就是 COALESCE
的用武之地。
A value (but not a key) can be an SQL NULL
.
所以COALESCE
无法区分这里NULL
的两种可能含义:
- 找不到密钥 'f2'`。
b.row_data->'f2'
returns 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[];
?
operator 检查单个键:
does hstore
contain key?
我需要编写一个查询(或函数),用存储在另一个 table 的 hstore
列中的值更新 table 中的现有记录。例如:
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 |
+----+----+------+----+
用 bar
中的值更新 foo
的 "best" 方法是什么?
注意:我将 最佳 定义为最容易编写代码。虽然性能始终很重要,但这是一个批处理作业,速度并不像用户等待结果时那样重要。
我正在使用 PostgreSQL 9.4。
所以您是在进行简单的更新?由于 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;
如果 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):
does
hstore
contain any of the specified keys?
如果不是这种情况,则根本不触摸该行是最便宜的。
否则,至少有一个(但不一定是所有!)列收到 UPDATE
。这就是 COALESCE
的用武之地。
A value (but not a key) can be an SQL
NULL
.
所以COALESCE
无法区分这里NULL
的两种可能含义:
- 找不到密钥 'f2'`。
b.row_data->'f2'
returnsNULL
作为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[];
?
operator 检查单个键:
does
hstore
contain key?