new*_*ere 4 sql postgresql case sql-update
我正在尝试使用postgres更新多行,我正在使用此代码:
UPDATE foobar SET column_a = CASE
WHEN column_b = '123' THEN 1
WHEN column_b = '345' THEN 2
END;
Run Code Online (Sandbox Code Playgroud)
如果我创建一个新表,它可以完美地运行,但是当在一个有800万行的大表上运行它时,它会无限期地挂起.我先在Admineer(Web界面)和控制台中尝试过.
但是这很好用:
UPDATE foobar SET column_a=1 WHERE column_b='123';
Run Code Online (Sandbox Code Playgroud)
我对在我的代码中实现这种方法犹豫不决,因为我将同时拥有数千个更新,并且更愿意将它们放在一个语句中.关于为什么第一个例子会挂起postgres的任何想法,第二个例子可以正常工作?我只是双重检查,我没有在桌子上应用规则.
该声明:
CASE
WHEN column_b = '123' THEN 1
WHEN column_b = '345' THEN 2
END;
Run Code Online (Sandbox Code Playgroud)
..只是简称:
CASE
WHEN column_b = '123' THEN 1
WHEN column_b = '345' THEN 2
ELSE NULL
ENDRun Code Online (Sandbox Code Playgroud)
意思是,如果没有WHERE子句,您的UPDATE语句不仅仅是"尝试",它实际上更新了表中的每一行,其中大多数都是NULL.
也许,NOT NULL对列的约束阻止了数据丢失......
我会立刻有成千上万的更新,并希望将它们放在一个声明中.
大型集合的速度更快(也更短):
UPDATE foobar f
SET column_a = val.a
FROM (
VALUES
(123, 1)
,(345, 2)
) val(b, a)
WHERE f.column_b = val.b
Run Code Online (Sandbox Code Playgroud)
加入一组 beatsCASE轻松迭代每一行的一长串分支.随着更长的列表,差异将迅速增长.
此外,请确保在任何一种方式都有索引column_b.
您可以VALUES使用任何表,视图或子选择替换表达式,从而产生适当的行.
注意:
我假设column_a并且column_b属于类型integer.在这种情况下,'123'您问题中的单引号从来没有帮助.您最好使用数字文字而不是字符串文字.(即使它也适用于字符串文字.)
字符串文字,'123'默认为unknown键入.
数字文字123 默认为integer- 或bigint/ numeric如果数字太大.
如果您正在处理非默认数据类型,则必须显式转换.看起来像:
...
FROM (
VALUES
('123'::sometype, '1'::sometype) -- first row defines row type
,('345', '2')
) val(b, a)
...
Run Code Online (Sandbox Code Playgroud)