【问题标题】:Can INSERT [...] ON CONFLICT be used for foreign key violations?可以将 INSERT [...] ON CONFLICT 用于外键违规吗?
【发布时间】:2016-03-16 14:35:13
【问题描述】:

给定

=> 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;

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

【问题讨论】:

    标签: sql postgresql sql-insert upsert postgresql-9.5


    【解决方案1】:

    是的,将您的输入行连接到引用的表,从而删除 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 可用于指定引发唯一约束或排除约束违规错误的替代操作。 (见下文ON CONFLICT Clause。)

    由于VALUES 表达式现在没有直接附加到INSERT,所以列类型不是从目标表派生的。使用非基本类型操作时,您可能需要显式强制转换输入值。见:

    【讨论】:

    • 确实非常好用,非常感谢。感谢您对ON CONFLICT 子句的澄清。
    • 如果在我尝试引用的同一张表上插入这项工作?所以像INSERT INTO entries ... JOIN entries
    • @JuanCarlosOropeza:你可以以同样的方式加入同一张表,只要确保加入条件只能匹配单个行。否则你必须使用不同的技术。
    • 包含不同类型(如时间戳和字节数组)的表会怎样。有没有什么方便的方法可以在FROM ( VALUES (1, 2, 'references two') -- more? ) val (entry_id, referenced_id, name) 中使用它们,而不是在 VALUES 中强制转换它们?
    • @madnan:这里有一些技术可以投射独立的VALUES 表达式的字段:stackoverflow.com/a/42217872/939860
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-08-02
    • 1970-01-01
    • 1970-01-01
    • 2023-02-05
    • 2018-08-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多