MYSQL删除外键,无法删除外键

1. 什么是参照完整性?
——————–
参照完整性(完整性约束)是数据库设计中的一个重要概念,当数据库中的一个表与一个或多个表进行关联时都会涉及到参照完整性。比如下面这个例子:
文章分类表 - categories
category_id     name
              SQL Server
              Oracle
              PostgreSQL
              SQLite

文章表 - articles
article_id      category_id     title
              1               aa
              2               bb
              4               cc

可见以上两个表之间是通过category_id,其中categories表有4条记录,articles表有3条记录。

然而可能因为某种原因我们删掉了categories 表中category_id=4的记录,而articles表却还是有一条category_id=4的记录,很明显,category_id=4的这条记录不应该存在在articles表中,这样会很容易造成数据错乱。

相反,外键关系(Foreign Key relationships)讨论的是父表(categories)与子表(articles)的关系,通过引入外键(Foreign Key)这个概念来保证参照完整性(Referential integrity),将使会数据库变的非常简单。比如,要要做到删除categories表中category_id=4记录的同时删除 articles 表中category_id=4的所有记录,如果没有引入外键的话,我们就必须执行2条SQL语句才行;如果有外键的话,可以很容易的用一条SQL语句就可以达到要求。

2. 使用外键的条件
—————–
MySQL只在v3.23.34版本以后才引入外键的,所以在这之前的版本就别想了:),除此之外,还必须具备以下几个条件:

    1) 在my.cnf配置文件中打开InnoDB引擎支持。
    # Uncomment the following if you are using InnoDB tables
    innodb_data_home_dir = /var/db/mysql/
    innodb_data_file_path = ibdata1:10M:autoextend
    innodb_log_group_home_dir = /var/db/mysql/
    innodb_log_arch_dir = /var/db/mysql/

    2) 相关联的表都必须采用InnoDB引擎。

    3) 相关联的字段都必须建立所以。
    MySQL v4.0版本以后,定义外键时会自动建立所以,所以在 v4.0 版本以前(含v4.0版本)必须手工定义索引。

    4) 相关联的字段必须采用类似的数据类型,或者说可转换的数据类型,当然相同类型是最好不过了。
    比如父表的字段是TINYINT类型,则子表只能采用TINYINT、SMALLINT、INT、BIGINT等几种类型。

3. 外键语法参考
—————
可以通过 CREATE TABLE 或者 ALTER TABLE 来定义外键。
CREATE TABLE 语法:
CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
    [(create_definition,…)]

create_definition:
    column_definition
| [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name,…) [reference_definition]

column_definition:
    col_name type [NOT NULL | NULL] [DEFAULT default_value]
        [AUTO_INCREMENT] [UNIQUE [KEY] | [PRIMARY] KEY]
        [COMMENT ’string’] [reference_definition]

index_col_name:
    col_name [(length)] [ASC | DESC]

reference_definition:
    REFERENCES tbl_name [(index_col_name,…)]
               [MATCH FULL | MATCH PARTIAL | MATCH SIMPLE]
               [ON DELETE reference_option]
               [ON UPDATE reference_option]

reference_option:
    RESTRICT | CASCADE | SET NULL | NO ACTION

ALTER TABLE 语法:
ALTER [IGNORE] TABLE tbl_name
    alter_specification [, alter_specification] …

alter_specification:
| ADD [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,…)
| ADD [CONSTRAINT [symbol]] UNIQUE [INDEX] [index_name] [index_type] (index_col_name,…)
| ADD [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name,…) [reference_definition]
| DROP FOREIGN KEY fk_symbol

4. 定义外键
———–
mysql> CREATE TABLE categories (
    -> category_id tinyint(3) unsigned NOT NULL AUTO_INCREMENT,
    -> name varchar(30) NOT NULL,
    -> PRIMARY KEY(category_id)
    -> ) ENGINE=INNODB;
Query OK, 0 rows affected (0.36 sec)

mysql> INSERT INTO categories VALUES (1, ‘SQL Server’), (2, ‘Oracle’), (3, ‘PostgreSQL’), (4, ‘MySQL’), (5, ‘SQLite’);
Query OK, 5 rows affected (0.48 sec)
Records: 5 Duplicates: 0 Warnings: 0

mysql> CREATE TABLE members (
    -> member_id INT(11) UNSIGNED NOT NULL,
    -> name VARCHAR(20) NOT NULL,
    -> PRIMARY KEY(member_id)
    -> ) ENGINE=INNODB;
Query OK, 0 rows affected (0.55 sec)

mysql> INSERT INTO members VALUES (1, ‘test’), (2, ‘admin’);
Query OK, 2 rows affected (0.44 sec)
Records: 2 Duplicates: 0 Warnings: 0

mysql> CREATE TABLE articles (
    -> article_id INT(11) unsigned NOT NULL AUTO_INCREMENT,
    -> title varchar(255) NOT NULL,
    -> category_id tinyint(3) unsigned NOT NULL,
    -> member_id int(11) unsigned NOT NULL,
    -> INDEX (category_id),
    -> FOREIGN KEY (category_id) REFERENCES categories (category_id),
    -> CONSTRAINT fk_member FOREIGN KEY (member_id) REFERENCES members (member_id),
    -> PRIMARY KEY(article_id)
    -> ) ENGINE=INNODB;
Query OK, 0 rows affected (0.63 sec)

注意:对于非InnoDB表,FOREIGN KEY子句会被忽略掉。
如果遇到如下错误:
ERROR 1005: Can’t create table ‘./test/articles.frm’ (errno: 150)
请仔细检查以下定义语句,常见的错误一般都是表类型不是INNODB、相关联的字段写错了、缺少索引等等。

至此categories.category_id和articles.category_id、members.member_id和 articles.member_id已经建立外键关系,只有 articles.category_id 的值存在与 categories.category_id 表中并且articles.member_id的值存在与members.member_id表中才会允许被插入或修改。例如:

mysql> INSERT INTO articles (category_id, member_id, title) VALUES (6, 1, ‘foo’);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`test/articles`, CONSTRAINT `articles_ibfk_1` FOREIGN KEY (`category_id`)REFERENCES `categories` (`id`))

mysql> INSERT INTO articles (category_id, member_id, title) VALUES (3, 3, ‘foo’);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`test/articles`, CONSTRAINT `fk_member` FOREIGN KEY (`member_id`) REFERENCES `members` (`member_id`))

可见上面两条语句都会出现错误,因为在categories表中并没有category_id=6、members表中也没有member_id=3的记录,所以不能插入。而下面这条SQL语句就可以。

mysql> INSERT INTO articles (category_id, member_id, title) VALUES (3, 2, ‘bar’);
Query OK, 1 row affected (0.03 sec)

5. 删除外键定义
—————
不知道大家有没有发现,在前面定义外键的时候articles.member_id外键比articles.category_id子句多了一个CONSTRAINT fk_member ?
这个fk_member就是用来删除外键定义用的,如下所示:
mysql> ALTER TABLE articles DROP FOREIGN KEY fk_member;
Query OK, 1 row affected (0.25 sec)
Records: 1 Duplicates: 0 Warnings: 0

这样articles.member_id外键定义就被删除了,但是如果定义时没有指定CONSTRAINT fk_symbol (即外键符号)时该怎么删除呢?别急,没有指定时,MySQL会自己创建一个,可以通过以下命令查看:

mysql> SHOW CREATE TABLE articles;
+———-+————————————+
| Table    | Create Table                       |
+———-+————————————+
| articles | CREATE TABLE `articles` (
`article_id` int(11) unsigned NOT NULL auto_increment,
`category_id` tinyint(3) unsigned NOT NULL,
`member_id` int(11) unsigned NOT NULL,
`title` varchar(255) NOT NULL,
PRIMARY KEY (`article_id`),
KEY `category_id` (`category_id`),
KEY `member_id` (`member_id`),
CONSTRAINT `articles_ibfk_1` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1          |
+———-+————————————+
1 row in set (0.01 sec)

可以看出articles.category_id的外键符号为articles_ibfk_1,因为就可以执行以下命令删除外键定义:

mysql> ALTER TABLE articles DROP FOREIGN KEY articles_ibfk_1;
Query OK, 1 row affected (0.66 sec)
Records: 1 Duplicates: 0 Warnings: 0

6. 总结
——-
引入外键的缺点是会使速度和性能下降,当然外键所带来的优点还有很多,本文仅讨论如何定义、删除外键。至于外键的实际应用将会在以后的文章中介绍。

原文链接:http://blog.youkuaiyun.com/zskcy/archive/2008/01/27/2069016.aspx

<think>好的,我现在需要帮用户解决如何在MySQL删除约束的问题。首先,我得回忆一下用户之前的提问和我的回答。用户之前询问了如何用DROP删除字段,现在则转向约束的删除,这可能是因为他们在实际操作中遇到了相关的问题,比如删除字段时因为有约束而失败。 接下来,我需要查阅用户提供的引用内容,特别是引用2、3、4,因为它们提到了约束的错误和处理方法。比如引用2中提到了错误1451,说明约束导致无法删除父表记录,用户可能已经遇到了类似的问题,现在想了解如何删除约束本身。 用户的问题明确要求正确的语法,因此我需要确保回答中包含具体的SQL语句。根据引用3,约束在创建时需要名称,因此在删除时也需要使用这个名称。如果用户不知道名称,可能需要先查询,这部分需要详细说明步骤,比如使用SHOW CREATE TABLE命令。 另,引用4提到了删除和更新行为,这可能与删除后的操作有关,但用户当前的问题主要集中在如何删除,而不是其行为。不过,考虑到用户可能有后续操作,可以简要提及这些行为的影响,但主要聚焦在删除步骤。 需要注意的是,用户可能对MySQL机制不太熟悉,所以需要解释每一步的作用,比如为什么需要先知道名称,如何安全地删除,以及删除后的影响,比如数据一致性问题。同时,要提醒用户删除后,应用层可能需要处理原本由保证的数据完整性,这点在引用1中提到,阿里规范建议在应用层处理,所以这也是一个重要的注意事项。 用户还可能关心删除时的常见错误,比如不存在或名称错误,需要给出解决方案,如验证是否存在。此,如果用户使用的是图形工具如Workbench,可能需要不同的步骤,但用户的问题集中在语法上,所以主要提供命令行方法,但可以提到工具的使用作为补充。 总结步骤应该是:1. 查找名称;2. 使用ALTER TABLE DROP FOREIGN KEY语句;3. 处理可能的相关索引。同时,提供示例和注意事项,确保用户能安全操作,避免数据丢失或结构问题。最后,相关问题可以引导用户了解的其他操作,比如创建或修改,但根据用户当前问题,可能更倾向于如何恢复或处理删除后的影响。</think>#### MySQL 删除约束的完整操作指南 在 MySQL删除约束需要明确**名称**,并通过 `ALTER TABLE` 语句执行操作。以下是具体步骤及注意事项: --- ### 一、核心语法 ```sql ALTER TABLE `从表名` DROP FOREIGN KEY `约束名称`; ``` **参数说明**: - **从表名**:定义约束的表(子表) - **约束名称**:创建时指定的约束名(可通过 `SHOW CREATE TABLE` 查询) **操作示例**: ```sql -- 删除从表 orders 中名为 fk_user_id 的约束 ALTER TABLE `orders` DROP FOREIGN KEY `fk_user_id`; ``` > **注意**:删除约束后,**索引不会自动删除**,需手动清理(见下文第三部分)[^3][^4]。 --- ### 二、完整操作流程 #### 1. 查询约束名称 使用 `SHOW CREATE TABLE` 获取定义信息: ```sql SHOW CREATE TABLE `orders`; /* 输出示例: CREATE TABLE `orders` ( `id` int NOT NULL, `user_id` int DEFAULT NULL, ... CONSTRAINT `fk_user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ) ENGINE=InnoDB; */ ``` 定位 `CONSTRAINT` 后的名称(如 `fk_user_id`)[^3]。 #### 2. 执行删除操作 ```sql -- 删除约束 ALTER TABLE `orders` DROP FOREIGN KEY `fk_user_id`; -- 删除关联的索引(可选) ALTER TABLE `orders` DROP INDEX `user_id`; -- 索引名通常与字段名一致 ``` #### 3. 验证结果 通过 `SHOW CREATE TABLE` 再次检查是否已移除。 --- ### 三、注意事项 1. **索引残留问题** - 删除约束后,MySQL **不会自动删除关联的索引**,需手动执行 `DROP INDEX` 释放存储空间[^4]。 2. **操作权限要求** - 需对目标表拥有 `ALTER` 权限 3. **数据一致性风险** - 删除约束后,**数据库不再自动校验关联数据**,需通过应用层逻辑确保数据完整性[^1] 4. **依赖对象影响** - 若被存储过程、触发器引用,需同步修改相关逻辑 --- ### 四、常见错误及解决 **错误1:`ERROR 1091 (42000): Can't DROP 'fk_user_id'; check that column/key exists`** - **原因**:名称拼写错误或不存在 - **解决**:通过 `SHOW CREATE TABLE` 确认名称 **错误2:`ERROR 1217 (23000): Cannot delete or update a parent row`** - **原因**:尝试删除主表字段时未解除约束 - **解决**:先删除约束,再操作主表字段[^2] --- ### 五、约束与性能权衡 根据阿里开发规范建议: - 高并发场景下,**优先通过应用层逻辑替代约束**,避免锁竞争和性能损耗[^1] - 事务型系统中可保留约束,但需配合 `ON DELETE CASCADE` 等级联策略优化操作效率[^4] --- ####
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值