2013-03-19 68 views
392

是否有可能暂时禁用MySQL中的约束?如何暂时禁用MySQL中的外键约束?

我有两个Django模型,每个模型都有一个到另一个的ForeignKey。由于ForeignKey约束,删除模型的实例会返回错误:

cursor.execute("DELETE FROM myapp_item WHERE n = %s", n) 
transaction.commit_unless_managed() #a foreign key constraint fails here 

cursor.execute("DELETE FROM myapp_style WHERE n = %s", n) 
transaction.commit_unless_managed() 

是否可以临时禁用约束并删除?

+3

要么我不明白你想做的事,或者你正在做什么**非常,非常非常难看**。即使你能做到,你也不应该这样做。 – Dariusz 2013-03-19 14:06:13

+3

删除并重新应用FK _is_更改您的分贝。你试图蔑视允许系统看到某种感觉的那些限制,它没有考虑到FK可能是暂时的事情,如果它确实知道的话,它会惊慌失措。 – 2013-03-19 14:07:07

+1

你想要做什么很奇怪。但是你使用哪个数据库? – andrefsp 2013-03-19 14:08:33

回答

922

尝试DISABLE KEYS

SET FOREIGN_KEY_CHECKS=0; 

确保

SET FOREIGN_KEY_CHECKS=1; 

+6

这是为整个mysql或仅仅是会话设置的东西吗? – tipu 2013-10-31 21:41:42

+9

我相信这是每个​​会话。 – 2013-11-04 15:02:50

+1

http://stackoverflow.com/questions/8538636/mysql-set-foreign-key-checks – 2013-11-04 15:04:22

21

不是禁用约束,而是将其永久修改为ON DELETE SET NULL。这将完成类似的事情,你不必打开和关闭钥匙检查。像这样:

ALTER TABLE tablename1 DROP FOREIGN KEY fk_name1; //get rid of current constraints 
ALTER TABLE tablename2 DROP FOREIGN KEY fk_name2; 

ALTER TABLE tablename1 
    ADD FOREIGN KEY (table2_id) 
     REFERENCES table2(id) 
     ON DELETE SET NULL //add back constraint 

ALTER TABLE tablename2 
    ADD FOREIGN KEY (table1_id) 
     REFERENCES table1(id) 
     ON DELETE SET NULL //add back other constraint 

有这个(http://dev.mysql.com/doc/refman/5.5/en/alter-table.html)读这(http://dev.mysql.com/doc/refman/5.5/en/create-table-foreign-keys.html)。

+5

当心篡改表格可能需要很长时间,最好将“FOREIGN_KEY_CHECKS”的服务器全局设置为0,并在肮脏工作完成后将其恢复。此外它可能会锁定写入你的表。 – Aki 2014-01-13 14:57:05

+0

在更改远程列类型时,是否不会引用该参考? (看起来我的客户将一个修改过的临时表重命名为原始表名。) – 2016-03-03 10:37:55

2

如果键字段为空,那么你也可以将值设置为空试图删除它之前:

cursor.execute("UPDATE myapp_item SET myapp_style_id = NULL WHERE n = %s", n) 
transaction.commit_unless_managed() 

cursor.execute("UPDATE myapp_style SET myapp_item_id = NULL WHERE n = %s", n) 
transaction.commit_unless_managed() 

cursor.execute("DELETE FROM myapp_item WHERE n = %s", n) 
transaction.commit_unless_managed() 

cursor.execute("DELETE FROM myapp_style WHERE n = %s", n) 
transaction.commit_unless_managed() 
86

要全局关闭外键约束,做到以下几点:

SET GLOBAL FOREIGN_KEY_CHECKS=0; 

并记得设置回当您完成

SET GLOBAL FOREIGN_KEY_CHECKS=1; 

警告:您应该只有在您进行单用户模式维护时才会这样做。因为它可能导致数据不一致。例如,当您使用mysqldump输出上传大量数据时,它会非常有帮助。

+0

这是我需要知道的,所以它不是很好的练习,但是这个家伙的答案应该是得分更高的... – ftrotter 2014-12-12 22:53:20

+1

这对我尝试后'最好的答案'对我来说不起作用。也许可以补充说明差异的解释。 – hexnet 2015-08-27 12:37:40

+4

@hexnet不同的是,只有SET FOREIGN_KEY_CHECKS只改变_current connection_的值,而SET GLOBAL ..改变_all connections_的值,包括将来的连接。如果你只是做'SET FOREIGN ..'在一个窗口中,然后尝试在不同的窗口中应用语句(通过不同的连接),该值在那里没有改变。使用'GLOBAL',同一个变量对于两个连接都具有相同的值。 – MatsLindh 2016-04-26 14:03:07

1

将外键约束设置为0不是一个好主意,因为如果这样做,数据库不会确保它不违反参照完整性。这可能会导致数据不准确,误导或不完整。

由于某种原因,您制作了一个外键:因为子列中的所有值应与父列中的值相同。如果没有外键约束,则子行的值可能不在父行中,这会导致数据不准确。

例如,假设您有一个供学生登录的网站,并且每个学生都必须以用户身份注册一个帐户。您有一个用于用户标识的表,其中用户标识为主键;和另一张学生帐户表,学生证作为专栏。由于每个学生都必须拥有一个用户标识,因此从学生帐户的学生标识表中引用一个引用用户标识表中的主键用户标识的外键是有意义的。如果没有外键检查,学生可能最终有一个学生ID和没有用户ID,这意味着学生可以得到一个帐户,而不是一个用户,这是错误的。

想象一下,如果它发生了大量的数据。这就是为什么你需要外键检查。

最好找出导致错误的原因。很可能,您正试图从父行中删除而不从子行中删除。在从父行删除之前尝试从子行删除。

+0

诚然,总是有一个权衡。 – Pacerier 2015-02-23 15:44:32

+10

没有人会说永远这样运行它。您关闭约束,批量加载一些数据,然后重新打开。没什么大不了的,人们总是这样做。 – bwawok 2015-11-17 17:39:21

+0

对于散装进口来说至少需要性能,这是很常见的。有时你只需要恢复数据,然后你就可以进行检查。 – 2017-02-14 23:43:58

30

当我想截断表,我通常只禁用外键约束,因为我继续回来这个答案,这是为未来的我:

SET FOREIGN_KEY_CHECKS=0; 
TRUNCATE TABLE table; 
SET FOREIGN_KEY_CHECKS=1; 
0

在phpMyAdmin,你可以选择多行,然后单击删除操作。您将进入一个列出删除查询的屏幕,您可以取消选中外键检查,然后单击是执行它们。

即使存在ON DELETE限制约束,也可以删除行。

1

phpmyadmin的一个非常简单的解决方案:在您的表中,转到SQL选项卡,编辑您想要运行的SQL命令后,在GO旁边有一个复选框'启用外键检查'。禁用此检查框并运行你的SQL。它会被自动重新检查。

+0

谢谢!确实解决方案'SET FOREIGN_KEY_CHECKS = 0; ..... SET FOREIGN_KEY_CHECKS = 1;'在PHPMyAdmin中不适合我,因为我忘记取消勾选'启用外键检查'复选框。在PHPMyAdmin中,您可以跳过这些SET命令并取消选中该复选框。 – Jan 2018-01-07 10:31:54

1

要全局关闭外键约束:

SET GLOBAL FOREIGN_KEY_CHECKS = 0; 

和积极的外键约束

SET GLOBAL FOREIGN_KEY_CHECKS = 1;