【问题标题】:Having 'foreign key mismatch' in a DELETE with multiple SELECTS在具有多个 SELECTS 的 DELETE 中存在“外键不匹配”
【发布时间】:2019-05-07 14:28:32
【问题描述】:

我正在使用(在 SQL 中)DELETE 和多个 SELECTs,但我得到一个外键不匹配。

SQL 语句为:

DELETE FROM tile_items 
WHERE tile_id IN (SELECT id 
                  FROM tiles 
                  WHERE house_id IN (SELECT id 
                                     FROM houses 
                                     WHERE owner <> 0 
                                       AND owner NOT IN (SELECT id FROM players)))

但我得到一个错误

外键不匹配 - “tile_items”引用“tiles”

奇怪的是,同样的语句,但使用SELECT * FROM,而不是DELETE FROM,会返回所有44条匹配记录。

我也尝试在字段前包含表名,但我得到了同样的错误。

DELETE FROM tile_items 
WHERE tile_items.tile_id IN (SELECT id 
                             FROM tiles 
                             WHERE tiles.house_id IN (SELECT id FROM houses 
                                                      WHERE houses.owner <> 0 
                                                        AND houses.owner NOT IN (SELECT id FROM players)))

不确定是否需要,但这里是表格:

CREATE TABLE "tile_items" 
(
    "tile_id" INTEGER NOT NULL,
    "world_id" INTEGER NOT NULL DEFAULT 0,
    "sid" INTEGER NOT NULL,
    "pid" INTEGER NOT NULL DEFAULT 0,
    "itemtype" INTEGER NOT NULL,
    "count" INTEGER NOT NULL DEFAULT 0,
    "attributes" BLOB NOT NULL,
    UNIQUE ("tile_id", "world_id", "sid"),
    FOREIGN KEY ("tile_id") REFERENCES "tiles" ("id")
)

CREATE TABLE "tiles" 
(
    "id" INTEGER NOT NULL,
    "world_id" INTEGER NOT NULL DEFAULT 0,
    "house_id" INTEGER NOT NULL,
    "x" INTEGER NOT NULL,
    "y" INTEGER NOT NULL,
    "z" INTEGER NOT NULL,
    UNIQUE ("id", "world_id"),
    FOREIGN KEY ("house_id", "world_id") REFERENCES "houses" ("id", "world_id")
)

由于错误仅引用了“tile_items”和“tiles”表,因此仅发布了这些架构。

希望有人能解释为什么我不能用这个语句删除但可以选择,谢谢。

【问题讨论】:

  • 在查看许多谷歌的错误消息的许多答案中的所有案例时,您学到了什么?
  • 好吧@philipxy,我以为我没有清楚正确地指定要删除的字段,所以我收到了错误,但正如 Kostya 指出的那样,这是关于需要在 CASCADE 上使用 DELETE .所以我会尝试改变我的表来添加它。将尽快发布结果。
  • 请在代码问题中给出minimal reproducible example--剪切&粘贴&运行代码;具有期望和实际输出的示例输入(包括逐字错误消息);明确的规范和解释。这包括您可以提供的最少代码,即您显示的代码可以通过您显示的代码扩展为不可以。 (调试基础。)您的 DBMS 是什么?您的“tile_items”FK 声明是非法的标准/通用 SQL,甚至在您运行 select 或 delete 之前——没有 PK/UNIQUE“tiles”(“id”)可供参考。你真的有选择运行吗?阅读 FK 声明。
  • 您应该始终使用您正在使用的 DBMS 标记 SQL 问题。我想这是 SQLite?

标签: sql foreign-keys


【解决方案1】:

奇怪的是,同样的语句,但使用 SELECT * FROM,而不是 DELETE FROM,会返回所有 44 条匹配记录。

这并不奇怪。该错误报告外键问题。存在外键以保证插入、更新和删除中的数据一致性。如果你只是选择数据,外键根本不重要。

外键不匹配 - “tile_items”引用“tiles”

这个错误实际上不是在你的删除语句上,而是在数据库及其外键上。您的声明是有效的,但您的 DBMS 允许无效的外键约束,并且仅在您插入、更新或删除数据时报告它们。在我看来,如果 DBMS 事先防止这种情况会更好。

在您的数据库中,您使用的是复合键。 tiles 表的唯一键是(id, world_id),因此瓦片 ID 仅在与世界 ID 组合时才有意义。相同的图块 ID 可以表示世界 X 中的一个图块和世界 Y 中的另一个图块。(最好不要将此列称为 id,因为它没有识别表中的记录。我建议非 ID 名称,例如 tile_notile_code 用于仅属于唯一标识列组的列。当然,house_id 也是如此。)

外键(“tile_id”)引用“tiles”(“id”)

在这里你想说tilestile_items 行引用。但它是什么?单独的图块 ID 不足以识别该表中的一行,您缺少世界 ID。必须是:

FOREIGN KEY (tile_id, world_id) REFERENCES tiles (id, world_id)

【讨论】:

  • 感谢您对这一切如此清楚。这里有两点......由于我使用的是BD Browser for SQLite,如所述:stackoverflow.com/questions/16537154/… “如果表已经存在并且您不想构建完整的脚本,那么您就完了幸运的是,一旦生成表,SQLite 不支持添加外键” 这使我无法更改表,也无法创建另一个表,因为所有系统都已构建,我只是在制作一个新脚本.总之,我无能为力吗?
  • 另外,我尝试在 SELECT 中使用复合键并且它可以工作,但不能使用 DELETE。 DELETE FROM tile_items WHERE (tile_id, world_id) IN (SELECT id, world_id FROM tile WHERE (house_id, world_id) IN (SELECT id, world_id FROM house WHERE owner 0 AND owner NOT IN (SELECT id FROM player)))跨度>
  • 我知道您不能ALTER TABLE tile_items ... 来删除错误的约束并添加正确的约束。但是为什么你说你不能创建一个表呢?您应该能够使用ALTER TABLE tile_items RENAME TO renamed_table; 重命名您现有的表。然后CREATE TABLE tile_items (...); 使用正确的外键约束,然后INSERT INTO tile_items SELECT * FROM renamed_table 复制其内容(最后是DROP TABLE renamed_table)。
猜你喜欢
  • 1970-01-01
  • 2012-12-14
  • 2021-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多