How to truncate a foreign key constrained table?
为什么在mygroup上的截断不起作用?即使我有ON DELETE CASCADE SET,我也得到:
ERROR 1701 (42000): Cannot truncate a table referenced in a foreign key constraint (mytest.instance, CONSTRAINT instance_ibfk_1 FOREIGN KEY (GroupID) REFERENCES mytest.mygroup (ID))
是的,你可以:
有了这些语句,您就有可能在表中插入不符合FOREIGN KEY约束的行。
- 我们是否必须设置foreign_key_checks=1;然后再设置?
- 我想你必须再次把它设置为1,因为这是默认值。
- 不,您没有。该设置仅在连接期间有效。一旦断开连接,下一个连接会将其设置回1。
- 这不会在引用的表中应用"on delete"事件,因此这不是完整的答案。
- @泽克姆斯我反对这个答案,因为它是最好的答案。如果我关闭了检查,我也不会期望任何外键事件传播。
- +1这在开发过程中非常方便,因为您的数据已经被破坏了…
- 这是一个很好的答案。完美的发展!
- 如果在phpmyadmin中使用,则只有在使用同一SQL窗口(由;分隔)中的所有事务时,这才有效。这是因为每个新的Web SQL调用都会将FOREIGN_KEY_CHECKS重置为1。
- 这在Mariadb也很管用。谢谢:
- 以下是查找孤立外键(恢复数据完整性)的非常好的方法,以防您感兴趣http://stackoverflow.com/a/12085689/997776
- @拼写是什么使您认为您希望连接的其余部分忽略外键规则?这听起来像是一个灾难的处方。
- 好吧,有两件事让我这么想:1.我从来没有见过在运行truncate和2之后希望保持连接活动的情况。我认为在任何允许灾难食谱的环境中运行truncate首先是一个坏主意。在我看来,你的问题虽然有效,但与我过去15年遇到的任何事情都没有关系。YMMV。
- @拼写,这样您就无法想象在截断某个内容之后,脚本将保存实体、进行日志记录或对数据库执行任何活动的任何场景。如果没有放回外国钥匙,任何这些都可能带来风险或进一步破坏完整性。
- @造粒依靠说"我有15年的经验,听我说"是最可靠的方式失去尊重任何人听你。证明力,伙计。
- 我根本不想让它听起来像我知道每一个可能的用例;即使我有150年的经验,我也不知道,也不会看到接近1%:-)截断一个表本身就已经是违反数据完整性的一个秘诀,而且我从来不会建议任何人首先在任何生产系统上这样做。回答你的问题:我完全可以想象它(我的意思是,它可以这样做,也许有人会这样做),但是——谢天谢地——我从来没有真正需要在一个关键任务系统上,如果我能做到这一点,我会先问自己黑客是怎么了。
- 谢谢!
- 这对我在libmysql - mysqlnd 5.0.12和phpMyAdmin 4.6.6上不起作用。只会产生与TRUNCATE相同的错误。此外,所有其他具有它的外键的表都是空的。乔治的回答确实有效。
- 请注意,这也是phpmyadmin中的一个功能,一旦进入SQL查询窗口,只需取消选中该框。
不能在表上应用FK约束(TRUNCATE与DELETE不同)。
要解决这一问题,请使用以下任一解决方案。两者都存在破坏数据完整性的风险。
选项1:
删除约束
执行TRUNCATE。
手动删除现在无处引用的行
创建约束
选项2:由用户447951在其答案中建议
- 实际上,先生,不是,用户447951给我们看了光!
- @Barjonah:实际上,它可能会破坏数据完整性(参见stackoverflow.com/questions/5452760/…)。所以,你在现实世界中所说的"光"被认为是一种不好的实践。附:谢谢投反对票。
- 以下是查找孤立外键(恢复数据完整性)的非常好的方法http://stackoverflow.com/a/12085689/997776
- 在截短前禁用外键也是一种很好的方法,我从stackoverflow.com/questions/8641703/&hellip成功地完成了它。
- @只有在开发期间才允许禁用外键检查。它破坏了任何现有的关系。Zerkms对数据完整性100%正确。除非计划完全清空工作数据库(或至少清空所有相关表),否则不能对工作数据库禁用外键检查。
- @BabyDead是对的,我只想要结构。
- 事实上,答案就是我所尝试的,并且得到了这个错误。SET FOREIGN_KEY_CHECKS = 0; TRUNCATE 导致错误"不能截断表……"的一个表;SET FOREIGN_KEY_CHECKS = 1;。
- 对于不需要担心数据完整性的测试环境来说,"风险解决方案"更好。
- @Artenesnogueira测试环境应该具有相同的规则。如果没有,那么您就不能确信测试中的工作会在prod中工作。
- @泽克斯:哦,是的,那是完全正确的。我是根据我目前所做的,即在运行每个测试之前清理数据库,做出这个评论的。因此,在开始运行测试之前,使用"有风险"的解决方案而不关心数据完整性来清除所有内容是有效的。
- "手动删除现在不引用任何位置的行"与尊重数据完整性毫无关系。在这种情况下可能会发生错误。外键不会失败。任何一个模仿删除外来行的用户脚本都不会失败。
- 谢谢,它起作用了!!!!干得好@zerkms
- @我认为你指的是开发环境。测试需要与生产一致,否则就不是"测试",而是"玩"。
- @Zerkms选项2为我工作
- @迪帕卡因,这很可悲。
- @泽克斯给你?
- @Deepakjain为您提供数据。您需要学习如何正确地处理数据,而不使其进入不一致的状态,即使在开发中也是如此。
- @谢谢你的建议。
- 多么愚蠢的设计决定
- 对Postgres来说,这是行不通的。有什么想法吗?
- @bhattraideb postgresql支持truncate cascade:postgresql.org/docs/current/sql-truncate.html
我只需要:
- Smart。当您仍然想删除所有记录时,您也可以重置自动增量。
- 这显然是最好的方法。没有丢失约束的风险,只需简单删除即可。值得注意的是,DELETE的表现比TRUNCATE慢。但是,由于这种操作通常很少执行,所以这并不重要。
- 如果您只想这样做,这是很好的,但是如果您有太多的行,那么DELETE可能是非常残忍的,因为它会命中日志,而TRUNCATE只会撕掉数据。这取决于用例。
- 当我使用DELETE语句时,它报告错误1175:您使用的是安全更新模式,只需添加set sql_safe_update s=0;然后就可以了
- 这是唯一真正正确的解决方案…另一个解决方案引入了整体性危险。
- 在使用该解决方案时,它将error 1175: You are using safe update mode,...change delete子句报告给DELETE FROM mydb.mytable where id != 0使其完美。
根据mysql文档,truncate不能用于具有外键关系的表。阿法克没有完全的替代品。
删除约束仍不调用on delete和on update。ATM唯一能想到的解决方案是:
- 删除所有行,删除外键,截断,重新创建键
- 删除所有行,重置自动增量(如果使用)
it would see truncate in mysql is not a complete feature yet(it also not invoke triggers).见评论
- 关于mysql的TRUNCATE是不完整的,截短不应该调用触发器等,如果是这样的话,就和DELETE一样了!它不区分行,因此无法执行与行相关的操作(如调用触发器或检查外键)。它在Oracle和SQL Server中的工作方式相同。
- 这个注释是我找到的关于为什么truncate不能忽略或跳过fk约束的最好解释。多谢西蒙M?肯齐。我也不同意truncate不是一个"完整的特性":它只是为了保持一致性而期望的行为。
- @卢西亚帕萨林,Postgres对在其截断部分添加级联没有任何问题,所以…
你可以做到
- 我试过了,但出现了以下错误:错误代码:1142。对于表"mytable",对用户"root"@"localhost"的删除命令被拒绝
虽然这个问题是在5年前被问到的,我不知道MySQL中有这个工具,但是现在如果您使用phpmyadmin,您可以简单地打开数据库,然后选择要截断的表。在底部有一个下拉列表,其中列出了许多选项。打开它并在标题"删除数据或表"下选择"空"选项。它会自动转到下一页,在该页的复选框中有一个名为"启用外键检查"的选项。只需取消选中它,然后按"是"按钮,所选表将被截断。可能在内部运行用户447951回答中建议的查询。但是从phpmyadmin接口使用非常方便。
答案确实是由Zerkms提供的,如选项1所述:
Option 1: which does not risk damage to data integrity:
Remove constraints
Perform TRUNCATE
Delete manually the rows that now have references to nowhere
Create constraints
棘手的部分是消除约束,所以我想告诉你,如果有人需要知道如何做到这一点:
运行SHOW CREATE TABLE 查询,查看您的外键名(下图中的红色框):
运行ALTER TABLE DROP FOREIGN KEY 。这将删除外键约束。
删除关联的索引(通过表结构页),就完成了。
要重新创建外键:
- 这帮了我!您还可以告诉我如何在删除约束后重建约束吗?
如果你使用phpmyadmin,很容易。
只需取消选中SQL选项卡下的Enable foreign key checks选项并运行TRUNCATE 。
只用级联
但要准备好级联删除)
如果表的数据库引擎不同,则会出现此错误,因此将其更改为innodb
获取旧的外键检查状态和SQL模式是截断/删除表的最佳方法,就像MySQLWorkbench在将模型与数据库同步时所做的那样。
1 2 3 4 5 6 7 8 9 10
| 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; |