ChatGPT解决这个技术问题 Extra ChatGPT

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

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

UPDATE table 
SET 
 column_a = 1 where column_b = '123',
 column_a = 2 where column_b = '345'
我一直试图在那个页面上找到它,但我无法得到它。我看到在哪里可以使用一个 where 语句更新多行,但我不知道如何使用它自己的 where 语句更新多行。我也搜索了谷歌并没有找到一个真正明确的答案,所以我希望有人可以提供一个明确的例子。

R
Roman Pekar

您还可以使用 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


此外,可能必须指定正确的数据类型。带有日期的示例:... from (values ('2014-07-21'::timestamp, 1), ('2014-07-20', 2), ... PostgreSQL Documentation 上的更多详细信息
效果很好,谢谢你的澄清!这方面的 Postgres 文档让人读起来有点混乱。
这很酷!没想到今天学习了一个新的sql构造
如何动态构建 VALUES(...) ?即向VALUES() 添加100 行。它可以是一个数组还是什么?
仅供参考,这是我正在寻找的最接近的版本。我们可以动态地将行添加到数组中。 ('f2924dda-8e63-264b-be55-2f366d9c3caa',false,'甜瓜球手'), ('d9ecd18d-34fd-5548-90ea-0183a72de849',true,'火锅叉') ]::item[] ) s; ; ``` stackoverflow.com/questions/57517980/…
A
Alex Hurst

基于@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', 'Connell'),
  (2, 'robert@duncan.info', 'Robert', 'Duncan')
) as u2(id, email, first_name, last_name)
where u2.id = u.id;

这似乎是他的解决方案.. UPDATE FROM (VALUES...) WHERE。它是如何仅基于?
我更喜欢这个答案,因为变量名更容易理解发生了什么。
哇。准确而清晰。我正在尝试在 GoLang 中实现类似的东西。那么我可以为值传递一个结构数组吗?像这样,from (values $1) 其中 $1 是一个结构数组。在上述情况下,strict 将具有 id、first_name 和 last_name 作为属性。
z
zero323

是的你可以:

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


这是错误的...您将更新所有行,即使它不是 '123' 也不是 '345'。您应该使用 WHERE column_b IN ('123','456')...
我认为 '456' 应该是 '345'
如果您在最后一个 WHEN ? THEN ? 行之后添加 ELSE column_b,那么该列将设置为其当前值,从而防止发生 MatheusQI 所说的事情。
那不是他要求的……他需要更新多个列,而不是根据列 B 设置列 A。
这不正是 OP 要求的 - 只有 column_a 需要更新(基于 column_b 的值),而不是多个列,对吧?
O
Omar

要在单个查询中更新多行,您可以试试这个

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 部分


T
Tal Barda

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

R
Ricky Boy

遇到类似的情况,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。


r
rjdb123

@Roman 感谢您的解决方案,对于使用节点的任何人,我使用此实用程序方法来抽出查询字符串以更新具有 n 条记录的 n 列。

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

常量有效载荷 = { 行:[ { id:1,ext_id:3 },{ id:2,ext_id:3 },{ id:3,ext_id:3 },{ id:4,ext_id:3 }]}; var result = updateMultiple('t', payload);控制台.log(结果); /* 返回的 qstring 是:UPDATE t AS t SET id = c.id, ext_id = c.ext_id FROM (VALUES (1,3),(2,3),(3,3),(4,3)) AS c(id,ext_id) WHERE c.id = t.id */ function updateMultiple(table, recordRows){ var valueSets = new Array(); var cSet = new Set(); var columns = new Array(); for (const [key, value] of Object.entries(recordRows.rows)) { var groupArray = new Array(); for ( const [key2, value2] of Object.entries(recordRows.rows[key])){ if(!cSet.has(key2)){ cSet.add(`${key2}`);列.push(key2); } groupArray.push(`${value2}`); } valueSets.push(`(${groupArray.toString()})`); } var valueSetsString = valueSets.join(); var setMappings = new String(); for(var i = 0; i < columns.length; i++){ var fieldSet = columns[i]; setMappings += `${fieldSet} = c.${fieldSet}`; if(i < columns.length -1){ setMappings += ', '; } } var qstring = `UPDATE ${table} AS t SET ${setMappings} FROM (VALUES ${valueSetsString}) AS c(${columns}) WHERE c.id = t.id`;返回qstring; }


A
Anton Bessonov

除了其他答案、评论和文档之外,数据类型转换可以放在使用中。这允许更轻松的复制粘贴:

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;

B
Binita Bharati

@zero323 提供的答案在 Postgre 12 上效果很好。如果有人对 column_b 有多个值(在 OP 的问题中提到)

UPDATE conupdate SET orientation_status = CASE
   when id in (66934, 39) then 66
   when id in (66938, 49) then 77
END
WHERE id IN (66934, 39, 66938, 49)

在上述查询中,id 类似于 column_borientation_status 类似于问题的 column_a


P
Peter Litvak

我认为接受的答案并不完全正确。它取决于顺序。这是一个示例,无法使用答案中的方法正常工作。

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;

我猜您查询的 VALUES 部分中的括号有误。它应该是 `VALUES ('2', false), ('1', true), ('3', false)` 然后它工作正常