如何截断外键约束表?
Posted
技术标签:
【中文标题】如何截断外键约束表?【英文标题】:How to truncate a foreign key constrained table? 【发布时间】:2011-07-24 02:11:24 【问题描述】:为什么mygroup
上的TRUNCATE 不起作用?
即使我有ON DELETE CASCADE SET
我得到:
错误 1701 (42000): 无法截断在外键约束中引用的表 (
mytest
.instance
, CONSTRAINTinstance_ibfk_1
FOREIGN KEY (GroupID
) REFERENCESmytest
.mygroup
(@98765423) @))
drop database mytest;
create database mytest;
use mytest;
CREATE TABLE mygroup (
ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY
) ENGINE=InnoDB;
CREATE TABLE instance (
ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
GroupID INT NOT NULL,
DateTime DATETIME DEFAULT NULL,
FOREIGN KEY (GroupID) REFERENCES mygroup(ID) ON DELETE CASCADE,
UNIQUE(GroupID)
) ENGINE=InnoDB;
【问题讨论】:
【参考方案1】:是的,你可以:
SET FOREIGN_KEY_CHECKS = 0;
TRUNCATE table1;
TRUNCATE table2;
SET FOREIGN_KEY_CHECKS = 1;
使用这些语句,您可能会将不遵守 FOREIGN KEY
约束的行放入表中。
【讨论】:
我们是否必须设置 SET FOREIGN_KEY_CHECKS=1;之后再来一次? 不,你没有。该设置仅在连接期间有效。断开连接后,下一次连接会将其设置回 1。 这不适用于引用表中的“ON DELETE”事件,因此这不是一个完整的答案。 如果在 phpMYADMIN 中使用,这仅在您使用同一 SQL 窗口中的所有事务时才有效(由;
分隔)。这是因为每个新的 Web SQL 调用都会将 FOREIGN_KEY_CHECKS
重置为 1。
如果您有兴趣http://***.com/a/12085689/997776,这是查找孤立外键(恢复数据完整性)的好方法【参考方案2】:
您不能 TRUNCATE
应用了 FK 约束的表(TRUNCATE
与 DELETE
不同)。
要解决此问题,请使用以下任一解决方案。两者都存在破坏数据完整性的风险。
选项 1:
-
移除约束
执行
TRUNCATE
手动删除现在引用 nowhere 的行
创建约束
选项 2: 由 user447951 在 their answer
中建议SET FOREIGN_KEY_CHECKS = 0;
TRUNCATE table $table_name;
SET FOREIGN_KEY_CHECKS = 1;
【讨论】:
@barjonah:实际上,它可能会破坏数据完整性(请参阅***.com/questions/5452760/…)。所以,你在现实世界中所谓的“光”被认为是一种不好的做法。 PS:感谢投反对票 这里有一个很好的方法可以找到孤立的外键(恢复数据完整性)@987654323@ @Dung 禁用外键检查只允许在开发阶段。它打破了任何现有的关系。 zerkms 在数据完整性方面是 100% 正确的。除非您打算完全清空它(或至少清空所有相关表),否则您不能在工作数据库上禁用外键检查 @Kamlesh 这不是我的解决方案,我建议不要这样做野蛮的方式。 @zerkms - 抱歉,如果我不清楚,当然 mysql 的 truncate 和 delete 实现是不同的。我要说的是 truncate 实现可能会更好 - 不要让它与 delete 语句相同。如果截断操作不违反 FK 约束(即子表为空),则没有理由错误地说它违反 FK - 因为不会有任何错误!这就是其他 RDBMS 截断实现的工作方式。【参考方案3】:我会简单地这样做:
DELETE FROM mytest.instance;
ALTER TABLE mytest.instance AUTO_INCREMENT = 1;
【讨论】:
聪明。当你无论如何都想删除所有记录时,你不妨重置自动增量。 这显然是最好的方法。没有失去约束的风险,只是简单的删除。值得注意的是DELETE
的执行速度比TRUNCATE
慢。但由于这个动作通常很少执行,所以这无关紧要。
如果您只想这样做,这很好,但是如果您有太多行,DELETE
可能会非常残酷 - 因为它会命中日志,而 TRUNCATE
只是将数据撕掉。真的取决于用例。
我在使用delete语句时报错1175: You are using safe update mode, just add SET SQL_SAFE_UPDATES = 0;然后就好了
使用此方案时,报告error 1175: You are using safe update mode,...
将删除子句更改为DELETE FROM mydb.mytable where id != 0
使其完美。【参考方案4】:
如果您使用的是 phpMyAdmin,则很容易。
只需取消选中SQL
选项卡下的Enable foreign key checks
选项并运行TRUNCATE <TABLE_NAME>
【讨论】:
【参考方案5】:你可以的
DELETE FROM `mytable` WHERE `id` > 0
【讨论】:
我试了一下bur,出现如下错误:Error Code: 1142. DELETE command denied to user 'root'@'localhost' for table 'mytable' 或者直接从mytable
删除
这不会重置自动增量。
您当然可以做到这一点。但是,如果您有一张包含 700 万条记录的表,请在等待时去吃午饭。
@AAEM 可能有一些问题。通常意味着您需要向数据库上的“root”用户授予删除权限,或者运行flush privileges
。见这里:***.com/questions/4767055/…【参考方案6】:
根据mysql documentation,TRUNCATE 不能用于具有外键关系的表。没有完全替代的 AFAIK。
删除约束仍然不会调用 ON DELETE 和 ON UPDATE。 我能 ATM 想到的唯一解决方案是:
删除所有行,删除外键,截断,重新创建键 删除所有行,重置 auto_increment(如果使用)似乎 MySQL 中的 TRUNCATE 还不是一个完整的功能(它也不会调用触发器)。
见评论
【讨论】:
关于 MySQL 的TRUNCATE
不完整的注释 - 截断不应该调用触发器等。如果确实如此,它将与 DELETE
相同!它与行无关,因此无法执行与行相关的操作(如调用触发器或检查外键)。它在 Oracle 和 Sql Server 中的工作方式相同。
为什么没有人提到 TRUNCATE 会重置 PRIMARY KEY?使用 DELETE 它不会重置 PRIMARY KEY,因此您的第一条记录将具有像 325579 这样的 ID,这很奇怪。 TRUNCATE 不应该以这种方式失败恕我直言。截断是重置表,所以无论如何它都应该重置。【参考方案7】:
在 MYSQL 数据库上测试
解决方案 1:
SET FOREIGN_KEY_CHECKS = 0;
TRUNCATE table1;
解决方案 2:
DELETE FROM table1;
ALTER TABLE table1 AUTO_INCREMENT = 1;
TRUNCATE table1;
这对我有用。我希望,这也会对你有所帮助。感谢您提出这个问题。
【讨论】:
解决方案 2 在 phpMyAdmin 中为我工作,但没有 TRUNCATE table1; 解决方案取决于 mysql 版本,这就是我发布 2 个解决方案的原因。乐于分享和帮助:) @Novasol 是的,你是对的,它可以工作,但如果你运行 TRUNCATE table1;命令然后mysql表索引将在内部自动设置为0,当您将此表1与任何其他表/表连接时将花费更少的时间。【参考方案8】:虽然有人问过这个问题,但我不知道,但现在如果您使用 phpMyAdmin,您只需打开数据库并选择要截断的表即可。
在底部有一个包含许多选项的下拉菜单。打开它并选择标题Delete data or table
下的Empty
选项。
它会自动将您带到下一页,其中复选框中有一个名为 Enable foreign key checks
的选项。只需取消选择它并按下Yes
按钮,选定的表格就会被截断。
也许它在内部运行user447951's answer中建议的查询,但是从phpMyAdmin界面使用非常方便。
【讨论】:
【参考方案9】:答案确实是the one provided by zerkms,如选项1所述:
选项 1:不会有损害数据完整性的风险:
移除限制 执行截断 手动删除现在无处引用的行 创建约束
棘手的部分是移除约束,所以我想告诉你如何,以防有人需要知道如何做到这一点:
运行SHOW CREATE TABLE <Table Name>
查询以查看您的FOREIGN KEY的名称是什么(下图中的红框):
运行ALTER TABLE <Table Name> DROP FOREIGN KEY <Foreign Key Name>
。这将删除外键约束。
删除相关的索引(通过表结构页面),你就完成了。
重新创建外键:
ALTER TABLE <Table Name>
ADD FOREIGN KEY (<Field Name>) REFERENCES <Foreign Table Name>(<Field Name>);
【讨论】:
【参考方案10】:只需使用 CASCADE
TRUNCATE "products" RESTART IDENTITY CASCADE;
但要为级联删除做好准备)
【讨论】:
OP 标记了 MySQL。虽然这在 Postgres 中有效,但在 MySQL 中不正确。【参考方案11】:获取旧的外键检查状态和 sql 模式是在将模型同步到数据库时像 Mysql Workbench 那样截断/删除表的最佳方法。
SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;`
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES';
DROP TABLE TABLE_NAME;
TRUNCATE TABLE_NAME;
SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
【讨论】:
【参考方案12】:如果表的数据库引擎不同,您将收到此错误,因此请将它们更改为 InnoDB
ALTER TABLE my_table ENGINE = InnoDB;
【讨论】:
【参考方案13】:另一种解决方法是删除表中的所有行,然后重置自动增量列:
delete from table_name where 1
然后运行:
ALTER TABLE table_name AUTO_INCREMENT = 1
【讨论】:
以上是关于如何截断外键约束表?的主要内容,如果未能解决你的问题,请参考以下文章