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

使用PostgreSQL更新同一查询中的多行,sql,postgresql,Sql,Postgresql,我希望在一条语句中更新PostgreSQL中的多行。有没有一种方法可以做到以下几点 UPDATE table SET column_a = 1 where column_b = '123', column_a = 2 where column_b = '345' 是的,你可以: UPDATE foobar SET column_a = CASE WHEN column_b = '123' THEN 1 WHEN column_b = '345' THEN 2 END WHE

我希望在一条语句中更新PostgreSQL中的多行。有没有一种方法可以做到以下几点

UPDATE table 
SET 
 column_a = 1 where column_b = '123',
 column_a = 2 where column_b = '345'
是的,你可以:

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')
工作证明:

您还可以使用语法和映射表。如果要更新多个列,则更具通用性:

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;

基于@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;

假设您有一个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;

遇到类似的场景,CASE表达式对我很有用

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

报告-此处是一个表,帐户id与上述报告id相同。上面的查询会将1条记录(与条件匹配的记录)设置为true,将所有不匹配的记录设置为false

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

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

如果不需要附加条件,则删除此查询的
部分

除了其他答案、注释和文档外,还可以使用数据类型转换。这样可以更轻松地进行复制粘贴:

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

我认为公认的答案并不完全正确。它依赖于顺序。下面是一个无法正确使用答案中的方法的示例

create table xxx (
    id varchar(64),
    is_enabled boolean
);

insert into xxx (id, is_enabled) values ('1',true);
insert into xxx (id, is_enabled) values ('2',true);
insert into xxx (id, is_enabled) values ('3',true);

UPDATE public.xxx AS pns
        SET is_enabled         = u.is_enabled
            FROM (
            VALUES
         (
            '3',
            false
         ,
            '1',
            true
         ,
            '2',
            false
         )
        ) AS u(id, is_enabled)
            WHERE u.id = pns.id;

select * from xxx;
因此,问题仍然存在,有没有一种方法可以以独立于秩序的方式实现这一点

----尝试了几件事情后,这似乎与订单无关

UPDATE public.xxx AS pns
        SET is_enabled         = u.is_enabled
            FROM (
            SELECT '3' as id, false as is_enabled UNION
            SELECT '1' as id, true as is_enabled UNION
            SELECT '2' as id, false as is_enabled
         ) as u
            WHERE u.id = pns.id;

@Roman感谢您提供的解决方案,对于任何使用node的人,我使用这个实用方法输出一个查询字符串,用n条记录更新n列

遗憾的是,它只处理具有相同列的n条记录,所以recordRows参数非常严格

const有效载荷={
行:[
{
id:1,
分机号码:3
},
{
id:2,
分机号码:3
},
{
id:3,
分机号码:3
} ,
{
id:4,
分机号码:3
} 
]
};
var结果=updateMultiple('t',有效载荷);
控制台日志(结果);
/*
返回的qstring为:
将t更新为t SET id=c.id,ext_id=c.ext_id FROM(值(1,3)、(2,3)、(3,3)、(4,3))为c(id,ext_id),其中c.id=t.id
*/
函数updateMultiple(表、记录行){
var valueSets=新数组();
var cSet=新集合();
var columns=新数组();
for(Object.entries(recordRows.rows))的常量[key,value]{
var groupArray=新数组();
对于Object.entries(recordRows.rows[key])的(const[key2,value2]){
如果(!cSet.has(键2)){
cSet.add(`${key2}`);
按(键2);
}
push(`${value2}`);
}
push(`(${groupArray.toString()})`);
}
var valuesetstring=valueSets.join();
var setMappings=新字符串();
对于(var i=0;i}
我一直试图在那页上找到它,但找不到。我知道可以使用一个where语句更新多行,但我不知道如何使用自己的where语句更新多行。我也搜索了谷歌,没有找到一个真正明确的答案,所以我希望有人能提供一个明确的例子。对不起,我的错误。更新。这是错误的。。。您将更新所有行,即使它不是
'123'
'345'
。你应该在('123','456')中使用
WHERE列_b
…我认为
'456'
应该是
'345'
如果你在最后一个
之后添加
ELSE列_b
?然后?
line然后该列将被设置为其当前值,从而防止Matheuski所说的情况发生。这不是他所要求的。。他需要更新多个列,而不是基于列B设置列A。这不正是OP要求的吗?只有列A需要更新(基于列B的值),而不是多个列,对吗?此外,可能还必须指定正确的数据类型。带有日期的示例:
。。。从(values('2014-07-21'::timestamp,1),('2014-07-20',2),…
Works上的更多详细信息非常好,感谢您的澄清!Postgres文档对此有点让人困惑。太酷了!今天没想到学习新的sql构造如何动态生成值(…)?即在值中添加100行().可能是一个数组还是什么的?@Charlie木匠 如果您想动态构建它,那么您可能在某个地方有数据?为什么不能从表中更新它?这似乎是他的解决方案..从(值…)更新在哪里。它是如何建立的?我更喜欢这个答案,因为变量名更容易理解正在发生的事情。哇。精确而清晰。我正试图在GoLang中实现类似的东西。那么我可以为值传递一个结构数组吗?类似这样的,
from(values$1)
其中$1是一个结构数组。在上述情况下,strict将id、first\u name和last\u name作为属性。