代码之家  ›  专栏  ›  技术社区  ›  Suren Aznauryan

带有联接和外键约束的SQL Delete

  •  1
  • Suren Aznauryan  · 技术社区  · 6 年前

    使用 10.0.31-MariaDB-1~jessie .

    我有两张桌子: provider_contact provider_contact_x_role 哪里 contact_id 提供商联系人角色 表具有对的外键引用 id 提供商联系人 桌子。

    当我运行以下查询时,结果为success:

    DELETE cr, c
    FROM provider_contact_x_role AS cr
    INNER JOIN provider_contact AS c
    ON cr.contact_id = c.id
    WHERE c.is_test_contact = 0;
    

    当我运行下一个查询时:

    DELETE cr, c
    FROM provider_contact_x_role AS cr
    INNER JOIN provider_contact AS c
    ON cr.contact_id = c.id
    WHERE c.email_address <> 'suren@test.com';
    

    结果是出现以下错误:

    Cannot delete or update a parent row: a foreign key constraint fails 
    (`ins_db`.`provider_contact_x_role`, CONSTRAINT 
    `FK_contact_id--provider_contact.id` FOREIGN KEY (`contact_id`) 
    REFERENCES `provider_contact` (`id`))
    

    注意,这两个查询之间的唯一区别是 WHERE 条件。

    问题:

    1) SQL中是否有任何东西可以确保在执行这些查询时 提供商联系人角色 是否先被删除?

    2) 知道这两个查询有什么不同吗(为什么第一个查询成功,第二个查询失败)?

    2 回复  |  直到 6 年前
        1
  •  1
  •   PhoneixS Oskar Dajnowicz    6 年前

    摘自MySQL文档:

    如果使用涉及InnoDB tables的多表DELETE语句 对于有外键约束的情况,MySQL优化器可能 按不同于它们的顺序处理表 父/子关系。在这种情况下,语句失败并滚动 回来。相反,您应该从单个表中删除并依赖 InnoDB提供的删除功能会导致其他表 相应修改。

    如果你用 EXPLAIN 您将看到它更喜欢首先按主表筛选(和删除),因为它需要它来进行连接。

    如果你使用 INNER JOIN ,你可以试试 STRAIGHT_JOIN 这和 内部连接 只不过,左表总是在右表之前读取,并按要实现的删除顺序放置表。

    除了级联之外,还可以使用 SET FOREIGN_KEY_CHECKS=0; .

        2
  •  0
  •   Ranielle Canlas    6 年前

    你能先删除你的 提供商联系人 表而不是 提供商联系人角色 因为它从 联系人id 外键。

    DELETE c, cr
    FROM provider_contact AS c
    INNER JOIN provider_contact_x_role AS cr
    ON c.id = cr.contact_id
    WHERE c.email_address <> 'suren@test.com';