首页 数据库 mysql教程 为mysql数据表添加外键(三)总结

为mysql数据表添加外键(三)总结

Jun 07, 2016 pm 03:46 PM
innodb mysql 外键 总结 支持 数据表 添加

InnoDB也支持外键约束。InnoDB中对外键约束定义的语法看起来如下: [CONSTRAINT symbol ] FOREIGN KEY [ id ] ( index_col_name , ...) REFERENCES tbl_name ( index_col_name , ...) [ON DELETE {RESTRICT | CASCADE | SET NULL | NO ACTION}] [ON UPDATE {

InnoDB也支持外键约束。InnoDB中对外键约束定义的语法看起来如下:

<span>[CONSTRAINT <em>symbol</em>] FOREIGN KEY [<em>id</em>] (<em>index_col_name</em>, ...)</span>
登录后复制
<span><span>    </span>REFERENCES <em>tbl_name</em> (<em>index_col_name</em>, ...)</span>
登录后复制
登录后复制
<span><span>    </span>[ON DELETE {RESTRICT | <font>CASCADE</font> | SET NULL | NO ACTION}]</span>
登录后复制
登录后复制
<span><span>    </span>[ON UPDATE {RESTRICT | <font>CASCADE</font> | SET NULL | NO ACTION}]</span>
登录后复制
登录后复制

外键定义服从下列情况:

·         所有tables必须是InnoDB型,它们不能是临时表。

·         在引用表中,必须有一个索引,外键列以同样的顺序被列在其中作为第一列。这样一个索引如果不存在,它必须在引用表里被自动创建。

·         在引用表中,必须有一个索引,被引用的列以同样的顺序被列在其中作为第一列。

·         不支持对外键列的索引前缀。这样的后果之一是BLOB和TEXT列不被包括在一个外键中,这是因为对这些列的索引必须总是包含一个前缀长度。

·         如果CONSTRAINTsymbol被给出,它在数据库里必须是唯一的。如果它没有被给出,InnoDB自动创建这个名字。

InnoDB拒绝任何试着在子表创建一个外键值而不匹配在父表中的候选键值的INSERT或UPDATE操作。一个父表有一些匹配的行的子表,InnoDB对任何试图更新或删除该父表中候选键值的UPDATE或DELETE操作有所动作,这个动作取决于用FOREIGN KEY子句的ON UPDATE和ON DETETE子句指定的referential action。当用户试图从一个父表删除或更新一行之时,且在子表中有一个或多个匹配的行,InnoDB根据要采取的动作有五个选择:

·         CASCADE: 从父表删除或更新且自动删除或更新子表中匹配的行。ON DELETE CASCADE和ON UPDATE CASCADE都可用。在两个表之间,你不应定义若干在父表或子表中的同一列采取动作的ON UPDATE CASCADE子句。

·         SET NULL: 从父表删除或更新行,并设置子表中的外键列为NULL。如果外键列没有指定NOT NULL限定词,这就是唯一合法的。ON DELETE SET NULL和ON UPDATE SET NULL子句被支持。

·         NO ACTION: 在ANSI SQL-92标准中,NO ACTION意味这不采取动作,就是如果有一个相关的外键值在被参考的表里,删除或更新主要键值的企图不被允许进行(Gruber, 掌握SQL, 2000:181)。 InnoDB拒绝对父表的删除或更新操作。

·         RESTRICT: 拒绝对父表的删除或更新操作。NO ACTION和RESTRICT都一样,删除ON DELETE或ON UPDATE子句。(一些数据库系统有延期检查,并且NO ACTION是一个延期检查。在MySQL中,外键约束是被立即检查的,所以NO ACTION和RESTRICT是同样的)。

·         SET DEFAULT: 这个动作被解析程序识别,但InnoDB拒绝包含ON DELETE SET DEFAULT或ON UPDATE SET DEFAULT子句的表定义。

当父表中的候选键被更新的时候,InnoDB支持同样选择。选择CASCADE,在子表中的外键列被设置为父表中候选键的新值。以同样的方式,如果在子表更新的列参考在另一个表中的外键,更新级联。

注意,InnoDB支持外键在一个表内引用,在这些情况下,子表实际上意味这在表内附属的记录。

InnoDB需要对外键和被引用键的索引以便外键检查可以快速进行且不需要一个表扫描。对外键的索引被自动创建。这是相对于一些老版本,在老版本中索引必须明确创建,否则外键约束的创建会失败。

在InnoDB内,外键里和被引用列里相应的列必须有类似的内部数据类型,以便它们不需类型转换就可被比较。整数类型的大小和符号必须相同。字符串类型的长度不需要相同。如果你指定一个SET NULL动作,请确认你没有在子表中宣告该列为为NOT NULL

如果MySQL从CREATE TABLE语句报告一个错误号1005,并且错误信息字符串指向errno 150,这意思是因为一个外键约束被不正确形成,表创建失败。类似地,如果ALTER TABLE失败,且它指向errno 150, 那意味着对已变更的表,外键定义会被不正确的形成。你可以使用SHOW INNODB STATUS来显示一个对服务器上最近的InnoDB外键错误的详细解释。

注释:InnoDB不对那些外键或包含NULL列的被引用键值检查外键约束。

对SQL标准的背离:如果在父表内有数个行,其中有相同的被引用键值,然后InnoDB在外键检查中采取动作,就仿佛其它有相同键值的父行不存在一样。例如,如果你已定义一个RESTRICT类型的约束,并且有一个带数个父行的子行,InnoDB不允许任何对这些父行的删除。

居于对应外键约束的索引内的记录,InnoDB通过深度优先选法施行级联操作。

对SQL标准的背离: 如果ON UPDATE CASCADE或ON UPDATE SET NULL递归更新相同的表,之前在级联过程中该表一被更新过,它就象RESTRICT一样动作。这意味着你不能使用自引用ON UPDATE CASCADE或者ON UPDATE SET NULL操作。这将阻止级联更新导致的无限循环。另一方面,一个自引用的ON DELETE SET NULL是有可能的,就像一个自引用ON DELETE CASCADE一样。级联操作不可以被嵌套超过15层深。

对SQL标准的背离: 类似一般的MySQL,在一个插入,删除或更新许多行的SQL语句内,InnoDB逐行检查UNIQUE和FOREIGN KEY约束。按照SQL的标准,默认的行为应被延迟检查,即约束仅在整个SQL语句被处理之后才被检查。直到InnoDB实现延迟的约束检查之前,一些事情是不可能的,比如删除一个通过外键参考到自身的记录。

注释:当前,触发器不被级联外键的动作激活。

一个通过单列外键联系起父表和子表的简单例子如下:

<span>CREATE TABLE parent(id INT NOT NULL,</span>
登录后复制
<span><span>                    </span>PRIMARY KEY (id)</span>
登录后复制
<span>) TYPE=INNODB;</span>
登录后复制
登录后复制
<span>CREATE TABLE child(id INT, parent_id INT,</span>
登录后复制
<span><span>                   </span>INDEX par_ind (parent_id),</span>
登录后复制
<span><span>                   </span>FOREIGN KEY (parent_id) REFERENCES parent(id)</span>
登录后复制
<span><span>                     </span>ON DELETE <font><font>CASCADE</font></font></span>
登录后复制
<span>) TYPE=INNODB;</span>
登录后复制
登录后复制

如下是一个更复杂的例子,其中一个product_order表对其它两个表有外键。一个外键引用一个product表中的双列索引。另一个引用在customer表中的单行索引:

<span>CREATE TABLE product (category INT NOT NULL, id INT NOT NULL,</span>
登录后复制
<span><span>                      </span>price DECIMAL,</span>
登录后复制
<span><span>                      </span>PRIMARY KEY(category, id)) TYPE=INNODB;</span>
登录后复制
<span>CREATE TABLE customer (id INT NOT NULL,</span>
登录后复制
<span><span>                      </span>PRIMARY KEY (id)) TYPE=INNODB;</span>
登录后复制
<span>CREATE TABLE product_order (no INT NOT NULL AUTO_INCREMENT,</span>
登录后复制
<span><span>                      </span>product_category INT NOT NULL,</span>
登录后复制
<span><span>                      </span>product_id INT NOT NULL,</span>
登录后复制
<span><span>                      </span>customer_id INT NOT NULL,</span>
登录后复制
<span><span>                      </span>PRIMARY KEY(no),</span>
登录后复制
<span><span>                      </span>INDEX (product_category, product_id),</span>
登录后复制
<span><span>                      </span>FOREIGN KEY (product_category, product_id)</span>
登录后复制
<span><span>                        </span>REFERENCES product(category, id)</span>
登录后复制
<span><span>                        </span>ON UPDATE <font>CASCADE</font> ON DELETE RESTRICT,</span>
登录后复制
<span><span>                      </span>INDEX (customer_id),</span>
登录后复制
<span><span>                      </span>FOREIGN KEY (customer_id)</span>
登录后复制
<span><span>   </span><span>                     </span>REFERENCES customer(id)) TYPE=INNODB;</span>
登录后复制

InnoDB允许你用ALTER TABLE往一个表中添加一个新的外键约束:

<span>ALTER TABLE yourtablename</span>
登录后复制
<span><span>    </span>ADD [CONSTRAINT <em>symbol</em>] FOREIGN KEY [<em>id</em>] (<em>index_col_name</em>, ...)</span>
登录后复制
<span><span>    </span>REFERENCES <em>tbl_name</em> (<em>index_col_name</em>, ...)</span>
登录后复制
登录后复制
<span><span>    </span>[ON DELETE {RESTRICT | <font>CASCADE</font> | SET NULL | NO ACTION}]</span>
登录后复制
登录后复制
<span><span>    </span>[ON UPDATE {RESTRICT | <font>CASCADE</font> | SET NULL | NO ACTION}]</span>
登录后复制
登录后复制

记住先创建需要的索引。你也可以用ALTER TABLE往一个表添加一个自引用外键约束。

InnoDB也支持使用ALTER TABLE来移除外键:

<span>ALTER TABLE <em>yourtablename</em> DROP FOREIGN KEY <em>fk_symbol</em>;</span>
登录后复制

当年创建一个外键之时,如果FOREIGN KEY子句包括一个CONSTRAINT名字,你可以引用那个名字来移除外键。另外,当外键被创建之时,fk_symbol值被InnoDB内部保证。当你想要移除一个外键之时,要找出标记,请使用SHOW CREATE TABLE语句。例子如下:

<span>mysql> <strong>SHOW CREATE TABLE ibtest<chmetcnv tcsc="0" numbertype="1" negative="False" hasspace="False" sourcevalue="11" unitname="C">11c</chmetcnv>/G</strong></span>
登录后复制
<span>*************************** 1. row ***************************</span>
登录后复制
<span><span>       </span>Table: ibtest<chmetcnv tcsc="0" numbertype="1" negative="False" hasspace="False" sourcevalue="11" unitname="C">11c</chmetcnv></span>
登录后复制
<span>Create Table: CREATE TABLE `ibtest<chmetcnv tcsc="0" numbertype="1" negative="False" hasspace="False" sourcevalue="11" unitname="C">11c</chmetcnv>` (</span>
登录后复制
<span><span>  </span>`A` int(11) NOT NULL auto_increment,</span>
登录后复制
<span><span>  </span>`D` int(11) NOT NULL default '0',</span>
登录后复制
<span><span>  </span>`B` varchar(200) NOT NULL default '',</span>
登录后复制
<span><span>  </span>`C` varchar(175) default NULL,</span>
登录后复制
<span><span>  </span>PRIMARY KEY<span>  </span>(`A`,`D`,`B`),</span>
登录后复制
<span><span>  </span>KEY `B` (`B`,`C`),</span>
登录后复制
<span><span>  </span>KEY `C` (`C`),</span>
登录后复制
<span><span>  </span>CONSTRAINT `0_38775` FOREIGN KEY (`A`, `D`)</span>
登录后复制
<span>REFERENCES `ibtest<chmetcnv tcsc="0" numbertype="1" negative="False" hasspace="False" sourcevalue="11" unitname="a">11a</chmetcnv>` (`A`, `D`)</span>
登录后复制
<span>ON DELETE <font>CASCADE</font> ON UPDATE <font>CASCADE</font>,</span>
登录后复制
<span><span>  </span>CONSTRAINT `0_38776` FOREIGN KEY (`B`, `C`)</span>
登录后复制
<span>REFERENCES `ibtest<chmetcnv tcsc="0" numbertype="1" negative="False" hasspace="False" sourcevalue="11" unitname="a">11a</chmetcnv>` (`B`, `C`)</span>
登录后复制
<span>ON DELETE <font>CASCADE</font> ON UPDATE <font><font>CASCADE</font></font></span>
登录后复制
<span>) ENGINE=INNODB CHARSET=latin1</span>
登录后复制
<span>1 row in set (0.01 sec)</span>
登录后复制
登录后复制
<span>mysql> <strong>ALTER TABLE ibtest<chmetcnv tcsc="0" numbertype="1" negative="False" hasspace="False" sourcevalue="11" unitname="C">11c</chmetcnv> DROP FOREIGN KEY 0_38775;</strong></span>
登录后复制

InnoDB解析程序允许你在FOREIGN KEY ... REFERENCES ...子句中用`(backticks)把表和列名名字围起来。InnoDB解析程序也考虑到lower_case_table_names系统变量的设置。

InnoDB返回一个表的外键定义作为SHOW CREATE TABLE语句输出的一部分:

<span>SHOW CREATE TABLE <em>tbl_name</em>;</span>
登录后复制

从这个版本起,mysqldump也将表的正确定义生成到转储文件中,且并不忘记外键。

你可以如下对一个表显示外键约束:

<span>SHOW TABLE STATUS FROM <em>db_name</em> LIKE '<em>tbl_name</em>';</span>
登录后复制

外键约束被列在输出的Comment列。

当执行外键检查之时,InnoDB对它照看着的子或父记录设置共享的行级锁。InnoDB立即检查外键约束,检查不对事务提交延迟。

要使得对有外键关系的表重新载入转储文件变得更容易,mysqldump自动在转储输出中包括一个语句设置FOREIGN_KEY_CHECKS为0。这避免在转储被重新装载之时,与不得不被以特别顺序重新装载的表相关的问题。也可以手动设置这个变量:

<span>mysql> <strong>SET FOREIGN_KEY_CHECKS = 0;</strong></span>
登录后复制
<span>mysql> <strong>SOURCE <em>dump_file_name</em>;</strong></span>
登录后复制
<span>mysql> <strong>SET FOREIGN_KEY_CHECKS = 1;</strong></span>
登录后复制

如果转储文件包含对外键是不正确顺序的表,这就以任何顺序导入该表。这样也加快导入操作。设置FOREIGN_KEY_CHECKS为0,对于在LOAD DATA和ALTER TABLE操作中忽略外键限制也是非常有用的。

InnoDB不允许你删除一个被FOREIGN KEY表约束引用的表,除非你做设置SET FOREIGN_KEY_CHECKS=0。当你移除一个表的时候,在它的创建语句里定义的约束也被移除。

如果你重新创建一个被移除的表,它必须有一个遵从于也引用它的外键约束的定义。它必须有正确的列名和类型,并且如前所述,它必须对被引用的键有索引。如果这些不被满足,MySQL返回错误号1005 并在错误信息字符串中指向errno 150。

 
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
2 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
2 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

如何在 PHP 中使用 MySQL 备份和还原? 如何在 PHP 中使用 MySQL 备份和还原? Jun 03, 2024 pm 12:19 PM

在PHP中备份和还原MySQL数据库可通过以下步骤实现:备份数据库:使用mysqldump命令转储数据库为SQL文件。还原数据库:使用mysql命令从SQL文件还原数据库。

如何优化 PHP 中的 MySQL 查询性能? 如何优化 PHP 中的 MySQL 查询性能? Jun 03, 2024 pm 08:11 PM

可以通过以下方式优化MySQL查询性能:建立索引,将查找时间从线性复杂度降至对数复杂度。使用PreparedStatements,防止SQL注入并提高查询性能。限制查询结果,减少服务器处理的数据量。优化连接查询,包括使用适当的连接类型、创建索引和考虑使用子查询。分析查询,识别瓶颈;使用缓存,减少数据库负载;优化PHP代码,尽量减少开销。

如何使用 PHP 插入数据到 MySQL 表中? 如何使用 PHP 插入数据到 MySQL 表中? Jun 02, 2024 pm 02:26 PM

如何将数据插入MySQL表中?连接到数据库:使用mysqli建立与数据库的连接。准备SQL查询:编写一个INSERT语句以指定要插入的列和值。执行查询:使用query()方法执行插入查询,如果成功,将输出一条确认消息。

如何使用 PHP 创建 MySQL 表? 如何使用 PHP 创建 MySQL 表? Jun 04, 2024 pm 01:57 PM

使用PHP创建MySQL表需要以下步骤:连接到数据库。创建数据库(如果不存在)。选择数据库。创建表。执行查询。关闭连接。

如何在 PHP 中使用 MySQL 存储过程? 如何在 PHP 中使用 MySQL 存储过程? Jun 02, 2024 pm 02:13 PM

要在PHP中使用MySQL存储过程:使用PDO或MySQLi扩展连接到MySQL数据库。准备调用存储过程的语句。执行存储过程。处理结果集(如果存储过程返回结果)。关闭数据库连接。

如何修复 MySQL 8.4 上的 mysql_native_password 未加载错误 如何修复 MySQL 8.4 上的 mysql_native_password 未加载错误 Dec 09, 2024 am 11:42 AM

MySQL 8.4(截至 2024 年的最新 LTS 版本)中引入的主要变化之一是默认情况下不再启用“MySQL 本机密码”插件。此外,MySQL 9.0完全删除了这个插件。 此更改会影响 PHP 和其他应用程序

oracle数据库和mysql的区别 oracle数据库和mysql的区别 May 10, 2024 am 01:54 AM

Oracle数据库和MySQL都是基于关系模型的数据库,但Oracle在兼容性、可扩展性、数据类型和安全性方面更胜一筹;而MySQL则侧重速度和灵活性,更适合小到中等规模的数据集。①Oracle提供广泛的数据类型,②提供高级安全功能,③适合企业级应用程序;①MySQL支持NoSQL数据类型,②安全性措施较少,③适合小型到中等规模应用程序。

如何使用 PHP 删除 MySQL 表中的数据? 如何使用 PHP 删除 MySQL 表中的数据? Jun 05, 2024 pm 12:40 PM

PHP提供以下方法来删除MySQL表中的数据:DELETE语句:用于从表中删除匹配条件的行。TRUNCATETABLE语句:用于清空表中的所有数据,包括自增ID。实战案例:可以使用HTML表单和PHP代码从数据库中删除用户。表单提交用户ID,PHP代码使用DELETE语句从users表中删除匹配ID的记录。

See all articles