Fli*_*mzy 3 postgresql sql-update bulkupdate
假设我想做一个批量更新,设置A = B的集合一个值.这可以通过一系列UPDATE查询轻松完成:
UPDATE foo SET value='foo' WHERE id=1
UPDATE foo SET value='bar' WHERE id=2
UPDATE foo SET value='baz' WHERE id=3
Run Code Online (Sandbox Code Playgroud)
但现在我想我想要批量做这件事.我有一个包含id和新值的二维数组:
[ [ 1, 'foo' ]
[ 2, 'bar' ]
[ 3, 'baz' ] ]
Run Code Online (Sandbox Code Playgroud)
有没有一种有效的方法在单个SQL查询中执行这三个UPDATE?
我考虑过的一些解决方案:
临时表
CREATE TABLE temp ...;
INSERT INTO temp (id,value) VALUES (....);
UPDATE foo USING temp ...
Run Code Online (Sandbox Code Playgroud)
但这真的只会解决问题.尽管进行批量INSERT可能更容易(或至少不那么难看),但仍然至少有三个查询.
通过将数据对作为SQL数组传递来对输入进行非规范化.但这使得查询非常难看
UPDATE foo
USING (
SELECT
split_part(x,',',1)::INT AS id,
split_part(x,',',2)::VARCHAR AS value
FROM (
SELECT UNNEST(ARRAY['1,foo','2,bar','3,baz']) AS x
) AS x;
)
SET value=x.value WHERE id=x.id
Run Code Online (Sandbox Code Playgroud)
这使得可以使用单个查询,但使查询变得丑陋且效率低下(特别是对于混合和/或复杂数据类型).
有更好的解决方案吗?或者我应该求助于多个UPDATE查询?
通常,您希望从table具有足够索引的批量更新中轻松进行合并:
CREATE TEMP TABLE updates_table
( id integer not null primary key
, val varchar
);
INSERT into updates_table(id, val) VALUES
( 1, 'foo' ) ,( 2, 'bar' ) ,( 3, 'baz' )
;
UPDATE target_table t
SET value = u.val
FROM updates_table u
WHERE t.id = u.id
;
Run Code Online (Sandbox Code Playgroud)
所以你应该通过以下方式填充你的update_table:
INSERT into updates_table(id, val)
SELECT
split_part(x,',',1)::INT AS id,
split_part(x,',',2)::VARCHAR AS value
FROM (
SELECT UNNEST(ARRAY['1,foo','2,bar','3,baz'])
) AS x
;
Run Code Online (Sandbox Code Playgroud)
请记住:该id字段中的索引(或主键)updates_table很重要.(但对于像这样的小集合,可能由优化器选择hashjoin)
此外:对于更新,重要的是避免使用相同的值进行更新,这会导致创建额外的rowversions +以及在VACUUM提交更新后生成的活动:
UPDATE target_table t
SET value = u.val
FROM updates_table u
WHERE t.id = u.id
AND (t.value IS NULL OR t.value <> u.value)
;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4750 次 |
| 最近记录: |