使用PostgreSQL更新同一查询中的多行


192

我希望在一条语句中更新PostgreSQL中的多行。有没有办法做下面的事情?

UPDATE table 
SET 
 column_a = 1 where column_b = '123',
 column_a = 2 where column_b = '345'

我一直在尝试在该页面上找到它,但是我找不到它。我看到可以使用一个where语句在哪里更新多行,但是我不知道如何使用自己的where语句来更新多行。我还搜索了google,但没有找到真正明确的答案,因此我希望有人可以对此提供明确的示例。
newUserNameHere

抱歉,是我的错。更新。
zero323

Answers:


426

您还可以使用update ... from语法并使用映射表。如果要更新多个列,则可以更通用:

update test as t set
    column_a = c.column_a
from (values
    ('123', 1),
    ('345', 2)  
) as c(column_b, column_a) 
where c.column_b = t.column_b;

您可以添加任意多的列:

update test as t set
    column_a = c.column_a,
    column_c = c.column_c
from (values
    ('123', 1, '---'),
    ('345', 2, '+++')  
) as c(column_b, column_a, column_c) 
where c.column_b = t.column_b;

sql fiddle demo


11
同样,可能必须指定一种正确的数据类型。:与日期的一个例子... from (values ('2014-07-21'::timestamp, 1), ('2014-07-20', 2), ...在进一步的细节PostgreSQL文档
何Andias

效果很好,谢谢您的澄清!Postgres文档对此进行了一些令人困惑的阅读。
skwidbreth '16

52

根据@Roman的解决方案,您可以设置多个值:

update users as u set -- postgres FTW
  email = u2.email,
  first_name = u2.first_name,
  last_name = u2.last_name
from (values
  (1, 'hollis@weimann.biz', 'Hollis', 'O\'Connell'),
  (2, 'robert@duncan.info', 'Robert', 'Duncan')
) as u2(id, email, first_name, last_name)
where u2.id = u.id;

4
这似乎是他的解决方案。从(值...)更新。它是如何建立的?
埃文·卡罗尔

14
我更喜欢这个答案,因为变量名称使它更容易理解正在发生的事情。
乔恩·莱蒙

哇。精确清晰。我正在尝试在GoLang中实现这样的事情。那么我可以在适当的位置传递一个结构数组吗?像这样,from (values $1)$ 1是一个结构数组。在上述情况下,strict将具有id,first_name和last_name作为属性。
Reshma Suresh

26

是的你可以:

UPDATE foobar SET column_a = CASE
   WHEN column_b = '123' THEN 1
   WHEN column_b = '345' THEN 2
END
WHERE column_b IN ('123','345')

和工作证明:http : //sqlfiddle.com/#!2/97c7ea/1


8
这是错误的...您将更新所有行,即使不是'123'或者也不行'345'。您应该使用WHERE column_b IN ('123','456')...
MatheusOl 2013年

1
我认为'456'应该是'345'
Roman Pekar

2
如果ELSE column_b在最后WHEN ? THEN ?一行之后添加,则该列将被设置为其当前值,从而防止MatheusQI所说的发生。
凯文·奥里斯

1
那不是他要了..他需要根据山坳B.更新多个COLS,不设置山坳
Amalgovinus

这不是OP要求的吗-仅column_a需要更新(基于column_b的值),而不是多个列,对吗?
凯夫拉尔

3

遇到类似的情况,CASE表达式对我很有用。

UPDATE reports SET is_default = 
case 
 when report_id = 123 then true
 when report_id != 123 then false
end
WHERE account_id = 321;

报告-此处为表格,account_id与上述的report_ids相同。上面的查询将1条记录(符合条件的一条记录)设置为true,而所有不匹配的记录均设置为false。


2

要在单个查询中更新多,可以尝试执行以下操作

UPDATE table_name
SET 
column_1 = CASE WHEN any_column = value and any_column = value THEN column_1_value end,
column_2 = CASE WHEN any_column = value and any_column = value THEN column_2_value end,
column_3 = CASE WHEN any_column = value and any_column = value THEN column_3_value end,
.
.
.
column_n = CASE WHEN any_column = value and any_column = value THEN column_n_value end

如果您不需要其他条件,请删除and此查询的一部分


0

假设您有一个ID数组和一个等效的状态数组-这是一个示例,该示例说明如何使用数组的静态SQL(由于值不同而不会改变的sql查询):

drop table if exists results_dummy;
create table results_dummy (id int, status text, created_at timestamp default now(), updated_at timestamp default now());
-- populate table with dummy rows
insert into results_dummy
(id, status)
select unnest(array[1,2,3,4,5]::int[]) as id, unnest(array['a','b','c','d','e']::text[]) as status;

select * from results_dummy;

-- THE update of multiple rows with/by different values
update results_dummy as rd
set    status=new.status, updated_at=now()
from (select unnest(array[1,2,5]::int[]) as id,unnest(array['a`','b`','e`']::text[]) as status) as new
where rd.id=new.id;

select * from results_dummy;

-- in code using **IDs** as first bind variable and **statuses** as the second bind variable:
update results_dummy as rd
set    status=new.status, updated_at=now()
from (select unnest(:1::int[]) as id,unnest(:2::text[]) as status) as new
where rd.id=new.id;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.