Postgresql:仅在提供新值时才进行冲突更新

Postgresql: ON CONFLICT UPDATE only if new value has been provided

我有这个 table:

CREATE TABLE myTable (
  a VARCHAR(32),
  b VARCHAR(32) DEFAULT NULL,
  c VARCHAR(32) DEFAULT NULL,

  PRIMARY KEY (a)
);

和这个 "UPSERT" 类型查询:

INSERT INTO 
  myTable ( a,  b,  c)
  VALUES  (, , )
ON CONFLICT (a)
  DO UPDATE SET
    b = ,
    c = ,
RETURNING
  a, b, c
;

这按预期工作。如果我首先插入(json 为了符号方便):

{a:"a", b:"b", c:"c"}

然后我可以用这样的参数更新它:

{a:"a", b:"x", c:"y"}

我得到了预期的结果——{a:"a"} 记录更新了 bc 列。

但我也希望能够做到这一点:

{a:"a", c:"Q"}

并更新 c,同时保持 b 列不变。

当然,我需要右手边的某种表达式,但我不知道那是什么。我的直觉是这样的(SQL 伪代码):

...
  DO UPDATE SET
    b = ( | b)
    c = ( | c)
...

此处正确的语法是什么?或者,我应该使用完全不同的方法吗?

您可以使用 COALESCE()。这个想法是将 NULL 值传递给其中一个参数,然后你可以这样做:

INSERT INTO myTable (a,  b,  c)
VALUES  (, , ) 
DO UPDATE SET
    b = COALESCE(EXCLUDED.b, b)
    c = COALESCE(EXCLUDED.c, c)

当一条记录已经存在 a = </code> 或 <code> 被赋予一个 null 值,然后仅写入非 null 值。

缺点是此查询无法将 null 值分配给已存在的记录。

旁注:这使用伪 table EXCLUDED 而不是重复参数。

您可以使用 COALESCE() 并且不要忘记为 th13=] myTable 使用别名

INSERT INTO myTable as t (a,  b,  c)
VALUES  (, , ) 
DO UPDATE SET
    b = COALESCE(EXCLUDED.b, t.b)
    c = COALESCE(EXCLUDED.c, t.c)