用“ON CONFLICT DO UPDATE”更换违反两个不同约束的两行

时间:2018-06-03 00:58:26

标签: postgresql

假设我们有一个这样的表:

CREATE TABLE ctest (
    ID INTEGER,
    Value TEXT,
    Age INTEGER,
    Weight INTEGER,
    PRIMARY KEY (ID, Value), UNIQUE (Age, Weight));

我们已经有几行:

INSERT INTO ctest (ID, Value, Age, Weight) VALUES (0, 'second', 1, 2);
INSERT INTO ctest (ID, Value, Age, Weight) VALUES (0, 'first', 1, 3);

假设我们现在要插入违反primary keyunique约束的行:

INSERT INTO ctest (ID, Value, Age, Weight) VALUES (0, 'second', 1, 3)
    ON CONFLICT (ID, Value, Weight, Age) DO UPDATE SET
        ID = EXCLUDED.ID,
        Value = EXCLUDED.Value,
        Age = EXCLUDED.Age,
        Weight = EXCLUDED.Weight;

不,这不起作用:我们得到no unique or exclusion constraint matching the ON CONFLICT

如果在创建ctest表时,我们还添加了UNIQUE (ID, Value, Age, Weight)约束(正如一些研究表明这可能会有所帮助),这也不起作用,但我们得到了不同的排序错误:这次是关于ctest_pkey被违反且密钥(id, value)=(0, second)已经存在。

那么,定义模式和拼出insert语句的正确方法是什么,以便两行都被一个新行替换?

1 个答案:

答案 0 :(得分:1)

INSERT语句无法在冲突时删除。

要根据来条件删除现有行,请使用WITH ... DELETE ... RETURNING构造。

WITH del AS (DELETE FROM ctest 
             WHERE (Age=1 AND Weight=3)
                OR (ID = 0 AND Value = 'second')
             RETURNING 0, 'second', 1, 3
            )
INSERT INTO ctest (ID, Value, Age, Weight)
SELECT * 
FROM  del
ON CONFLICT DO NOTHING