MySQL 删除约束

11

我有一个表格,结构如下:

    CREATE TABLE `Lm_help` (
 `id` int(10) NOT NULL AUTO_INCREMENT,
 `section` int(10) NOT NULL,
 `language` int(10) NOT NULL,
 `title` varchar(255) NOT NULL,
 `text` text NOT NULL,
 `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
 PRIMARY KEY (`id`),
 UNIQUE KEY `unique_help` (`section`,`language`),
 KEY `language_constraint` (`language`),
 CONSTRAINT `language_constraint` FOREIGN KEY (`language`) REFERENCES `Lm_languages` (`id`),
 CONSTRAINT `section_constraint` FOREIGN KEY (`section`) REFERENCES `Lm_help_sections` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1

我需要删除“unique_help”键,但是我收到外键约束错误。

由于这个错误,我无法在这些中删除任何内容: section_constraint,language_constraint,unique_help。

以下是引用此内容的其他表:

CREATE TABLE `Lm_languages` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `name` varchar(255) NOT NULL,
 `code` varchar(255) NOT NULL,
 `status` int(11) DEFAULT NULL,
 `created_at` datetime NOT NULL,
 `updated_at` datetime NOT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1




CREATE TABLE `Lm_help_sections` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `name` varchar(255) NOT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1

你具体遇到了什么错误? - juergen d
unique_help不是主键,而是唯一索引。你遇到了什么错误? - Mad Dog Tannen
无法删除索引“language_constraint”:在外键约束中需要。 - viv
无法删除索引“unique_help”:在外键约束中需要。 - viv
请添加与 lm_help 相关的表格结构。 - juergen d
4个回答

20

问题在于unique_help (section, language)索引被section_constraint外键约束使用。因此,您无法在首先不删除约束的情况下删除索引。


解决这个问题的方法之一是先删除外键约束,然后再删除索引。

然后,您可以在(section)上添加一个(简单的)索引,并重新创建外键。

所有这些可以在一条语句中完成:

ALTER TABLE Lm_help
    DROP FOREIGN KEY section_constraint,   -- drop the FK so
    DROP INDEX unique_help,                -- the index can be dropped
                                           -- and then
    ADD INDEX section_IX (section),        -- add a new index
    ADD CONSTRAINT section_FK              -- so the FK can be recreated
        FOREIGN KEY (section) 
        REFERENCES Lm_help_sections (id)
  ;

SQL-Fiddle 进行过测试。


改进

我错了,不需要删除和重新创建约束。只要创建一个新的索引就可以删除索引:

ALTER TABLE Lm_help
    DROP INDEX unique_help,
    ADD INDEX section_IX (section) 
  ; 

SQL-Fiddle-2上进行了测试


谢谢,那个方法可行,我之前使用的是“drop index section_constraint”,但是不起作用,而“drop foreign key section_constraint”却可以……你能解释一下为什么吗? - viv
这是在MySQL中删除外键约束的语法。 - ypercubeᵀᴹ

8
ALTER TABLE Orders
DROP FOREIGN KEY 'language_constraint';

ALTER TABLE Orders
DROP FOREIGN KEY 'section_constraint';

执行删除查询语句。
ALTER TABLE Orders
ADD CONSTRAINT `language_constraint`
FOREIGN KEY (`language`)
REFERENCES `Lm_languages` (`id`);

ALTER TABLE Orders
ADD CONSTRAINT `section_constraint`
FOREIGN KEY (`section`)
REFERENCES `Lm_help_sections` (`id`);

1
谢谢Tushar,那个方法可行,但我不能接受两个答案... :) - viv

2

正如您的错误消息所示

(...)在 [引用外键的表] 中,必须有一个索引,其中引用的列以相同的顺序列出为第一列。

您必须找到引用表并从此(这些)其他表中删除外键约束。

抱歉,我太快地阅读了您的表定义。实际问题是相反的情况

MySQL 要求外键和引用键上必须有索引,以便外键检查可以快速进行且不需要表扫描。

要么首先删除 section_constraint 外键约束,要么在删除 UNIQUE 约束之前在 language 上创建新索引。


你可以看一下我使用的其他表的结构。 - viv
我的错, 请看我的新答案。 - RandomSeed

1
这里是一个存储过程,您可以在调用创建SQL之前调用它来删除外键。我修改了一个类似问题的答案,关于DROP PROCEDURE IF EXISTS 的回答者是:https://stackoverflow.com/users/166161/thomas-paine 示例调用:
CALL DropForeignKey (DATABASE(), 'tablename', 'keyname');

过程:

DELIMITER ;

/* DROP_FOREIGN_KEY */
DROP PROCEDURE IF EXISTS DropForeignKey;

DELIMITER //

CREATE PROCEDURE DropForeignKey(
IN param_schema VARCHAR(100),
IN param_table_name VARCHAR(100),
IN param_constraint_name VARCHAR(100)
) 

BEGIN
    IF EXISTS(
    SELECT NULL FROM information_schema.TABLE_CONSTRAINTS
    WHERE CONSTRAINT_NAME=param_constraint_name AND TABLE_NAME=param_table_name AND TABLE_SCHEMA = param_schema
    )
    THEN
        set @paramTable = param_table_name ;

    set @ParamConstraintName = param_constraint_name ;
    set @ParamSchema = param_schema;
    /* Create the full statement to execute */
    set @StatementToExecute = concat('ALTER TABLE `',@ParamSchema,'`.`',@paramTable,'` DROP FOREIGN KEY `',@ParamConstraintName,'` ');
    /* Prepare and execute the statement that was built */
    prepare DynamicStatement from @StatementToExecute ;
    execute DynamicStatement ;
    /* Cleanup the prepared statement */
    deallocate prepare DynamicStatement ;

END IF;
END //

DELIMITER ;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接