如何使用 PostgreSQL Upsert 在不同的 where 条件下使用 INSERT ON CONFLICT 语句更新多列

How to do multiple columns update on different where condition using PostgreSQL Upsert Using INSERT ON CONFLICT statement

假设我有一个像这样的 table

create schema test;
CREATE TABLE test.customers (
customer_id serial PRIMARY KEY,
name VARCHAR UNIQUE,
email VARCHAR NOT NULL,
active bool NOT NULL DEFAULT TRUE,
is_active_datetime                   TIMESTAMP(3) NOT NULL DEFAULT'1900-01-01T00:00:00.000Z'::timestamp(3)
updated_datetime                     TIMESTAMP(3) NOT NULL DEFAULT '1900-01-01T00:00:00.000Z'::timestamp(3),
);

现在如果我想更新 email 冲突 name

WHERE $tableName.updated_datetime < excluded.updated_datetime

我想在冲突 name 上更新 is_active_datetime,但此更新的条件是活动标志已更改。

WHERE customer.active != excluded.active

基本上想跟踪活动状态何时更改。所以我可以在这样的单个语句中做到这一点

初始插入:

insert  INTO test.customers (NAME, email)
VALUES
('IBM', 'contact@ibm.com'),
(
'Microsoft',
'contact@microsoft.com'
 ),
(
 'Intel',
 'contact@intel.com'
);

为了实现我的目的,我正在尝试这样的事情:

select * from test.customers;

INSERT INTO customers (name, email)
VALUES
(
'Microsoft',
'hotline@microsoft.com'
)
ON CONFLICT (name)
DO
UPDATE
SET customers.email = EXCLUDED.email
WHERE $tableName.updated_datetime < excluded.updated_datetime
on CONFLICT (name)
do
update
set is_active_datetime = current_timestamp()
WHERE customer.active != excluded.active ;

这可以吗?如何使用此方法执行此操作。

您可以在单个 DO UPDATE clause 中使用 CASE 条件更新多个列。

INSERT INTO customers  (
    name
    ,email
    ,updated_datetime
    )
VALUES (
    'Microsoft'
    ,'hotline@microsoft.com'
    ,now()
    ) ON CONFLICT(name) DO

UPDATE
SET email = CASE 
        WHEN customers.updated_datetime < excluded.updated_datetime
            THEN excluded.email
        ELSE customers.email --default when condition not satisfied
        END
    ,is_active_datetime = CASE 
        WHEN customers.active != excluded.active
            THEN current_timestamp
        ELSE customers.is_active_datetime
    END;

Demo