postgresql 用不同的条件更新表的不同列

svmlkihl  于 2023-04-05  发布在  PostgreSQL
关注(0)|答案(2)|浏览(169)

这里有一个SQL:

update table_name
set column1 = new_value1,
    column2 = new_value2
    
where id = 1;

update table_name
set column3 = new_value3,
    column4 = new_value4
    
where id = 3;

update table_name
set column5 = new_value5,
    column6 = new_value6,
    column7 = new_value7
    
where id = 6;

有什么方法可以让它更简单或更干净吗?

holgip5t

holgip5t1#

我们可以在同一个update语句中将其重写为all run,其中它为WHERE子句中匹配的每个id设置所有列,并在每个列上使用case表达式来决定设置相同的值或新值:

update table_name
set column1 = case when id = 1 then 'new_value1' else column1 end,
    column2 = case when id = 1 then 'new_value2' else column2 end,
    column3 = case when id = 3 then 'new_value3' else column3 end,
    column4 = case when id = 3 then 'new_value4' else column4 end,
    column5 = case when id = 6 then 'new_value5' else column5 end,
    column6 = case when id = 6 then 'new_value6' else column6 end,
    column7 = case when id = 6 then 'new_value7' else column7 end
where id IN (1, 3, 6);

我们可以进一步将其更改为在table-valued constructor上使用JOIN表达式:

UPDATE table_name t
INNER JOIN ( VALUES 
   ROW (1, 'new_value1', 'new_value2', NULL, NULL, NULL, NULL, NULL),
   ROW (3, NULL, NULL, 'new_value3', 'new_value4', NULL, NULL, NULL),
   ROW (6, NULL, NULL, NULL, NULL, 'new_value5', 'new_value6', 'new_value7')
) map(id, nv1, nv2, nv3, nv4, nv5, nv6, nv7) ON map.id = t.id
SET t.column1 = coalesce(map.nv1, t.column1),
    t.column2 = coalesce(map.nv2, t.column2),
    t.column3 = coalesce(map.nv3, t.column3),
    t.column4 = coalesce(map.nv4, t.column4),
    t.column5 = coalesce(map.nv5, t.column5),
    t.column6 = coalesce(map.nv6, t.column6),
    t.column7 = coalesce(map.nv7, t.column7);

这两种方法都有自动确保所有内容都在同一事务中的优点(更好的原子性,如果这是一个词的话),我喜欢第二种选择--尽管它的代码有点多--因为它将新值更像数据一样对待。
但是
我不会把它们称为“更简单”或“更干净”,你已经拥有的东西在这方面可能已经足够好了,除非你真的想要单一语句的好处。

holgip5t

holgip5t2#

使用参数创建一个函数或触发器。如果你有一个列列表要设置,一个列列表要检查,将数组作为参数传递给函数,并使用循环而不是像下面这样使用一个语句来构建字符串。在这个例子中,我只是为每一个变量而不是函数中的参数(作为变量)。
然后像这样使用动态SQL。

DECLARE sc1 varchar:= 'column1';
DECLARE sv1 varchar := 'new_value1';
DECLARE sc2 varchar:= 'column2';
DECLARE sv2 varchar := 'new_value2';
DECLARE wc1 varchar := 'id';
DECLARE wv1 varchar := '1';

EXECUTE 'update table_name set ' || sc1 || ' = ' || sv1 || ', ' || sc2 || ' = ' || sv2 || ' where ' || wc1 || ' = ' || wv1

create function build_query(sc1 varchar, 
                            sv1 varchar,
                            sc2 varchar,
                            sv2 varchar,
                            wc1 varchar,
                            wv1 varchar)
  returns text
as
$$
begin
    return EXECUTE 'update table_name set ' || sc1 || ' = ' || sv1 || ', ' || sc2 || ' = ' || sv2 || ' where ' || wc1 || ' = ' || wv1 ;
end;
$$
language plpgsql;

调用函数:

SELECT build_query('column1', 'new_value1', 'column2', 'new_value2', 'id', '1');

相关问题