使用PostgreSQL更新多行

使用PostgreSQL更新多行,sql,postgresql,Sql,Postgresql,我需要使用PostgreSQL更新同一sql事务中的多行。从下面的帖子: 我看到以下代码: 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; 但是,只有当您更新每组值的所有列

我需要使用PostgreSQL更新同一sql事务中的多行。从下面的帖子: 我看到以下代码:

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(而不是plpgsql)?

假设您不更新到
NULL
值,您可以使用:

UPDATE test t
    SET column_a = COALESCE(c.column_a, t.column_a),
        column_c = COALESCE(c.column_c, t.column_c
FROM (values ('123', 1, NULL),
             ('345', NULL, '+++')  
     ) c(column_b, column_a, column_c) 
WHERE c.column_b = t.column_b;
编辑:

如果值可以是
NULL
,则需要其他列来指定是否应使用该值:

UPDATE test t
    SET column_a = (CASE WHEN c.use_a THEN c.column_a::numeric ELSE t.column_a END),
        column_c = (CASE WHEN c.use_b THEN c.column_c::varchar ELSE t.column_c END)
FROM (values (123, 1, NULL, true, false),
             (345, NULL, '+++', false true)  
     ) c(column_b, column_a, column_c, use_a, use_c) 
WHERE c.column_b::int4 = t.column_b;
您的论点“仅当您正在更新每组值的所有列时”是不正确的。更新将只影响SET子句中提到的那些列。由于接受NULL作为新值,因此只需为特定列设置一个直接值:

update test t
    set column_a = c.column_a
      , column_c = c.column_c 
 from (values ('123', 1, NULL, 'Ignored Column')
            , ('345', NULL, '+++','Ignored Column')  
      ) c(column_b, column_a, column_c,column_d) 
where c.column_b = t.column_b ;

请参阅,特别是附加的列_d.

当我说“值集”时,我指的是set子句中提到的那些值。此外,“忽略”一栏可能给出,也可能不给出。那么“我不”是什么意思呢。在什么情况下,您不会更新值集中的列。这需要明确定义。您的编辑几乎可以工作,但在CASE语句中,您必须将值转换为与原始列值相同的类型,以获得一致的返回值。我使用postgreSQL 11.1对其进行了测试,并抛出了一个错误,说明了上述内容。我会看看是否可以编辑你的答案,然后我会把它标记为这个问题的实际答案。@TimMoses。没有理由怀疑这些列会有不同的类型;你的问题甚至没有提供样本数据。我的问题提供了样本数据“('123',1',--',('345',2',++')”。无论如何,对于上述解决方案的“工作”,它必须铸造到某些类型。是的,我没有在问题中提供类型或进一步的信息,但我只是说没有它们它将无法工作。