Отбрасывать внешний ключ только в том случае, если он существует

Я нахожусь в базе данных MySQL.

Я делаю это, но это не работает.

ALTER TABLE `object` DROP FOREIGN KEY IF EXISTS `object_ibfk_1`;

Я пытался поставить этот IF EXISTS везде, где мог. Как проверить, существует ли внешний ключ перед его удалением?

Ответы

Ответ 1

Если вы хотите удалить внешний ключ, если он существует, и не хотите использовать процедуры, вы можете сделать это таким образом (для MySQL):

set @var=if((SELECT true FROM information_schema.TABLE_CONSTRAINTS WHERE
            CONSTRAINT_SCHEMA = DATABASE() AND
            TABLE_NAME        = 'table_name' AND
            CONSTRAINT_NAME   = 'fk_name' AND
            CONSTRAINT_TYPE   = 'FOREIGN KEY') = true,'ALTER TABLE table_name
            drop foreign key fk_name','select 1');

prepare stmt from @var;
execute stmt;
deallocate prepare stmt;

Если есть внешний ключ, мы помещаем оператор alter table в переменную, и если мы не добавляем фиктивный оператор. И затем мы его выполним.

Ответ 2

Для большей повторной юзабилити вы действительно захотите использовать хранимую процедуру. Запустите этот код один раз на требуемой БД:

   DROP PROCEDURE IF EXISTS PROC_DROP_FOREIGN_KEY;
    DELIMITER $$
    CREATE PROCEDURE PROC_DROP_FOREIGN_KEY(IN tableName VARCHAR(64), IN constraintName VARCHAR(64))
    BEGIN
        IF EXISTS(
            SELECT * FROM information_schema.table_constraints
            WHERE 
                table_schema    = DATABASE()     AND
                table_name      = tableName      AND
                constraint_name = constraintName AND
                constraint_type = 'FOREIGN KEY')
        THEN
            SET @query = CONCAT('ALTER TABLE ', tableName, ' DROP FOREIGN KEY ', constraintName, ';');
            PREPARE stmt FROM @query; 
            EXECUTE stmt; 
            DEALLOCATE PREPARE stmt; 
        END IF; 
    END$$
    DELIMITER ;

После этого вы всегда можете заменить это:

ALTER TABLE `object` DROP FOREIGN KEY IF EXISTS `object_ibfk_1`;

с этим:

CALL PROC_DROP_FOREIGN_KEY('object', 'object_ibfk_1');

Затем ваш script должен гладко работать независимо от того, существует ли object_ibfk_1 или нет.

Много кредитов из-за: http://simpcode.blogspot.com.ng/2015/03/mysql-drop-foreign-key-if-exists.html

Ответ 3

IF EXISTS(
              SELECT *
              FROM INFORMATION_SCHEMA.STATISTICS
              WHERE INDEX_SCHEMA = DATABASE()
                    AND TABLE_NAME='myTable'
                    AND INDEX_NAME = 'myIndex')
        THEN

            ALTER TABLE `myTable` DROP FOREIGN KEY `myForeignKey`;

            ALTER TABLE `myTable` DROP INDEX `myIndex` ;

        END IF;

При создании ограничения внешнего ключа mysql автоматически создаст индекс в столбце с ссылкой. В приведенном выше примере показано, как проверить индекс в INFORMATION_SCHEMA, но есть гораздо больше информации для вас в информационной схеме. Ваше имя индекса указывает на то, что оно было создано для FK, поэтому вам придется сначала отказаться от FK, а затем отбросить индекс. Если вы снова создадите внешний ключ, mysql снова создаст индекс. Он нуждается в индексе для обеспечения ссылочной целостности без необходимости выполнять сканирование таблицы.

Если вы планировали создать новый индекс, содержащий один и тот же столбец, сначала нужно создать этот индекс (с этим столбцом, который будет использоваться как FK, первым в списке столбцов указанный для индекса). Теперь вы можете добавить свой FK обратно, и mysql будет рад использовать новый индекс, не создавая другого.

Изменить: быстро просмотреть индексы просто выполнить ПОКАЗАТЬ ИНДЕКСЫ из myTable;

Ответ 4

Какую базу данных вы используете?

Если SQL Server

if exists (select 1 from sys.objects where object_id = OBJECT_ID(N'[FKName]') AND      
parent_object_id = OBJECT_ID('TableName'))
alter table TableName drop constraint FKName