如何截断外键约束表?


648

为什么没有一个TRUNCATEmygroup工作?即使ON DELETE CASCADE SET我知道了:

错误1701(42000):无法截断在外键约束中引用的表(mytestinstance,CONSTRAINT instance_ibfk_1FOREIGN KEY(GroupID)参考mytestmygroupID))

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;

Answers:


1000

您不能TRUNCATE在上面应用FK约束的表(TRUNCATE与不一致DELETE)。

要变通解决此问题,使用这些解决方案之一。两者都存在破坏数据完整性的风险。

选项1:

  1. 消除约束
  2. 执行 TRUNCATE
  3. 手动删除现在无处引用的行
  4. 创建约束

选项2: user447951其答案中建议

SET FOREIGN_KEY_CHECKS = 0; 
TRUNCATE table $table_name; 
SET FOREIGN_KEY_CHECKS = 1;

46
@barjonah:实际上,它可能会破坏数据完整性(请参见stackoverflow.com/questions/5452760/…)。因此,您在现实世界中所谓的“光”被认为是一种不好的做法。PS:感谢downvote
zerkms

1
这是查找孤立的外键(恢复数据完整性)的一种很好的方法http://stackoverflow.com/a/12085689/997776
SandorRacz

截断之前禁用的外键也是一个很好的方式,我从源成功做到了:stackoverflow.com/questions/8641703/...
阮晋勇

2
@Dung仅在开发期间才允许禁用外键检查。它破坏了任何现有的关系。zerkms对于数据完整性是100%正确的。除非您打算完全清空它(或至少所有相关表),否则您不能禁用正在运行的数据库上的外键检查
NoobishPro 2016年

1
@Kamlesh这不是我的解决方案,我建议不要以这种野蛮的方式这样做。
zerkms

1308

是的你可以:

SET FOREIGN_KEY_CHECKS = 0;

TRUNCATE table1;
TRUNCATE table2;

SET FOREIGN_KEY_CHECKS = 1;

使用这些语句,您可能会冒险让表中的行不遵守FOREIGN KEY约束。


30
我们必须设置SET FOREIGN_KEY_CHECKS = 1吗?再来一次?
vinc3m1 '04年

77
不,你没有。该设置仅在连接期间有效。只要你断开连接,下一个连接将有其设置回1
的Pellmeister

7
这不会在引用的表中应用“ ON DELETE”事件,因此这不是一个完整的答案。
Omer Sabic 2012年

5
如果在PHPMYADMIN中使用,则只有在同一SQL窗口(以分隔;)中使用所有事务时,此方法才有效。这是因为每个新网页的SQL调用将重置FOREIGN_KEY_CHECKS为1
Sablefoste

1
如果您感兴趣的话,这是查找孤立外键(恢复数据完整性)的一种很好的方法http://stackoverflow.com/a/12085689/997776
SandorRacz

173

我只是用:

DELETE FROM mytest.instance;
ALTER TABLE mytest.instance AUTO_INCREMENT = 1;

5
聪明。无论如何,如果要删除所有记录,则最好重设自动增量。
winkbrace

6
显然,这是最好的方法。没有丢失约束的风险,只需简单地删除即可。值得注意的是,它的运行DELETE速度比慢TRUNCATE。但是由于通常很少执行此操作,所以这无关紧要。
phil294

如果这是您要做的一切,那很好,但是DELETE如果您有太多的行,那将是绝对残酷的-因为它会击中日志,而TRUNCATE只是撕裂数据。真的取决于用例。
杰夫,

1
当我使用delete语句时,它报告错误1175:您正在使用安全更新模式,只需添加SET SQL_SAFE_UPDATES = 0; 那很好
tyan

使用此解决方案时,它将报告error 1175: You are using safe update mode,...change delete子句以DELETE FROM mydb.mytable where id != 0使其完美。
张世和


13

根据mysql文档,TRUNCATE不能用于具有外键关系的表。没有完整的替代AFAIK。

删除约束仍然不会调用ON DELETE和ON UPDATE。我ATM可以想到的唯一解决方案是:

  • 删除所有行,删除外键,截断,重新创建键
  • 删除所有行,重置为auto_increment(如果使用)

MySQL中的TRUNCATE似乎还不是一个完整的功能(它也不会调用触发器)。 查看评论


7
关于MySQL TRUNCATE不完整的观点-截断不应该调用触发器等。如果确实如此,它将与DELETE!相同!它与行无关,因此无法执行与行相关的操作(如调用触发器或检查外键)。它在OracleSql Server中的工作方式相同。
SimonMᶜKenzie2015年


8

尽管有人问过这个问题,但我不知道,但是现在如果您使用phpMyAdmin,则只需打开数据库并选择要截断的表即可。

  • 在底部有很多选项的下拉菜单。打开它,然后选择Empty标题下的选项Delete data or table
  • 它会自动将您带到下一页,其中复选框名为Enable foreign key checks。只需取消选择它,然后按Yes按钮,所选表格将被截断。

也许它在内部运行user447951的答案中建议的查询,但是从phpMyAdmin界面使用它非常方便。


7

在MYSQL数据库上测试

解决方案1:

SET FOREIGN_KEY_CHECKS = 0;
TRUNCATE table1;

解决方案2:

DELETE FROM table1;
ALTER TABLE table1 AUTO_INCREMENT = 1;
TRUNCATE table1;

这对我有用。希望对您有帮助。感谢您提出这个问题。


6

答案确实zerkms提供的答案,如选项1所述

选项1:不会冒损坏数据完整性的风险:

  1. 消除约束
  2. 执行截断
  3. 手动删除现在无处引用的行
  4. 创建约束

棘手的部分是删除约束,所以我想告诉您如何操作,以防有人需要知道如何做:

  1. 运行SHOW CREATE TABLE <Table Name>查询以查看您的FOREIGN KEY的名称是什么(下图中的红色框):

    在此处输入图片说明

  2. 运行ALTER TABLE <Table Name> DROP FOREIGN KEY <Foreign Key Name>。这将删除外键约束。

  3. 删除关联的索引(通过表结构页面),就可以完成。

重新创建外键:

ALTER TABLE <Table Name>
ADD FOREIGN KEY (<Field Name>) REFERENCES <Foreign Table Name>(<Field Name>);

3

只需使用CASCADE

TRUNCATE "products" RESTART IDENTITY CASCADE;

但准备好级联删除)


3
OP标记为MySQL。虽然这在Postgres中有效,但在MySQL中是错误的。
彼得

1

如果表的数据库引擎不同,则会出现此错误,因此请将其更改为InnoDB

ALTER TABLE my_table ENGINE = InnoDB;

0

获取旧的外键检查状态和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;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.