INSERT [...] ON CONFLICT 可以用于外键违规吗?

Can INSERT [...] ON CONFLICT be used for foreign key violations?

给出

=> select * from referenced;
 referenced_id | name  
---------------+-------
             1 | one
             2 | two
             3 | three

=> select * from entries;
 entry_id | referenced_id |      name      
----------+---------------+------------------
        1 |             3 | references three

其中 referenced_identry_id 是主键。

我想要 entries 的插入语句,如果 entry_id 已经存在或引用的项目不存在,则跳过插入。第一个很容易做到:

INSERT INTO entries
VALUES (1, 2, 'references two')
ON CONFLICT (entry_id) DO NOTHING;

是否也可以在这里检查外键是否存在?

是的,将您的输入行连接到引用的 table,从而删除 FK 列上不匹配的行:

INSERT INTO entries(entry_id, referenced_id, name)
SELECT val.entry_id, val.referenced_id, val.name
FROM  (
  VALUES (1, 2, 'references two')
         -- more?
  ) val (entry_id, referenced_id, name)
JOIN   referenced USING (referenced_id)  -- drop rows without matching FK
ON     CONFLICT (entry_id) DO NOTHING;   -- drop rows with duplicate id

UPSERT 本身 (INSERT ... ON CONFLICT DO NOTHING) 仅对独特的违规行为做出反应。 The manual:

ON CONFLICT can be used to specify an alternative action to raising a unique constraint or exclusion constraint violation error. (See ON CONFLICT Clause below.)

由于 VALUES 表达式现在不直接附加到 INSERT,列类型不是从目标 table 派生的。在使用非基本类型时,您可能需要显式 cast 输入值。参见:

  • Casting NULL type when updating multiple rows