ON CONFLICT ... DO UPDATE SET 因重复行而失败

Ted*_*Ted 3 sql postgresql

我有下一个查询:

INSERT INTO loger(state, id, event_timestamp, other_event_timestamp)
VALUES 
   (1, 12, '2020-01-01T19:00:00.000Z', '2020-01-01T19:00:00.000Z'),
   (1, 12, '2020-01-01T19:00:00.000Z', '2020-01-01T19:00:00.000Z') 
    ON CONFLICT(id, event_timestamp) DO UPDATE SET state = excluded.state
Run Code Online (Sandbox Code Playgroud)

在执行过程中它失败并出现错误:

ERROR:  ON CONFLICT DO UPDATE command cannot affect row a second time
Run Code Online (Sandbox Code Playgroud)

ps 这些数据来自外部,所以我应该按原样将其传递给查询。

Gor*_*off 5

错误信息非常清楚。该ON CONFLICT子句引用表中已有的行。这在文档中进行了解释:

带有 ON CONFLICT DO UPDATE 子句的 INSERT 是一个“确定性”语句。这意味着该命令将不允许多次影响任何单个现有行;出现这种情况时会引发基数违规错误。建议插入的行在受仲裁索引或约束约束的属性方面不应相互重复。

(我添加了突出显示。)

您可以通过在查询中进行一些操作将其减少到一行。例如,以下插入任意一行:

INSERT INTO loger (state, id, event_timestamp, other_event_timestamp)
    SELECT DISTINCT ON (id, event_timestamp) state, id, event_timestamp, other_event_timestamp
    FROM (VALUES (1, 12, '2020-01-01T19:00:00.000Z', '2020-01-01T19:00:00.000Z'),
                 (1, 12, '2020-01-01T19:00:00.000Z', '2020-01-01T19:00:00.000Z') 
         ) v(state, id, event_timestamp, other_event_timestamp)
    ORDER BY id, event_timestamp
    ON CONFLICT(id, event_timestamp) DO UPDATE SET state = excluded.state;
Run Code Online (Sandbox Code Playgroud)

您还可以将代码构建为两个单独的INSERTs。

  • @尼洛克特。。。我当然没有重写“SET”子句。我认为OP在前五分钟改变了逻辑。 (2认同)