web-dev-qa-db-fra.com

Supprimer la clé étrangère uniquement si elle existe

Je suis sur une base de données MySQL.

Je fais ça, mais ça ne marche pas.

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

J'ai essayé de mettre ce SI EXISTE partout où je pouvais. Comment vérifier si une clé étrangère existe avant de la déposer?

25
Creditto

Si vous voulez supprimer une clé étrangère si elle existe et ne voulez pas utiliser de procédures vous pouvez le faire de cette façon (pour 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;

S'il y a une clé étrangère, nous mettons l'instruction alter table dans une variable et s'il n'y en a pas, nous mettons une instruction fictive. Et puis nous l'exécutons.

23
NikolaB

Pour une plus grande réutilisation, vous voudriez en effet utiliser une procédure stockée . Exécutez ce code une fois sur la base de données souhaitée:

   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 ;

Par la suite, vous pouvez toujours remplacer ceci:

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

avec ça:

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

Votre script devrait alors fonctionner correctement, que object_ibfk_1 existe réellement ou non.

Beaucoup de crédit en raison de: http://simpcode.blogspot.com.ng/2015/03/mysql-drop-foreign-key-if-exists.html

12
Ifedi Okonkwo
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;

Lorsque vous créez une contrainte de clé étrangère, mysql crée automatiquement un index sur la colonne référencée. L'exemple ci-dessus montre comment vérifier un index dans INFORMATION_SCHEMA, mais il y a beaucoup plus d'informations à vérifier dans schéma d'information . Votre nom d'index semble indiquer qu'il a été créé pour un FK, vous devez donc d'abord supprimer le FK, puis supprimer l'index. Si vous recréez la clé étrangère, mysql créera à nouveau l'index. Il a besoin d'un index pour appliquer l'intégrité référentielle sans avoir à effectuer une analyse de table.

Si votre intention était de créer un nouvel index contenant la même colonne, vous devez d'abord créer cet index (avec cette colonne, celle qui sera utilisée comme FK, étant la première de la liste des colonnes spécifiées pour le indice). Vous pouvez maintenant ajouter votre FK et mysql sera heureux d'utiliser le nouvel index sans en créer un autre.

Modifier: pour afficher rapidement les index, exécutez simplement SHOW INDEXES FROM myTable;

11
heruka

Dans la version actuelle de Mariadb 10.1.26 (nouveau Mysql), votre requête fonctionne:

Clé: MUL

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

Clé: <NULL>

1
IntCom

Quelle base de données utilisez-vous ??

Si 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
1
Jack Daniel's

Voici une solution de contournement pour le DROP FOREIGN KEY IF EXISTS, qui manque dans les versions MySQL et MariaDB avant v10.1.4. Vous pouvez également l'utiliser pour toutes les autres instructions de votre choix, qui devraient dépendre de l'existence d'un FOREIGN KEY (par exemple pour SELECT "info: foreign key exists." comme dans l'exemple ci-dessous).

-- DROP FOREIGN KEY IF EXISTS
SELECT
    COUNT(*)
INTO
    @FOREIGN_KEY_my_foreign_key_ON_TABLE_my_table_EXISTS
FROM
    `information_schema`.`table_constraints`
WHERE
    `table_schema` = 'my_database'
    AND `table_name` = 'my_table'
    AND `constraint_name` = 'my_foreign_key'
    AND `constraint_type` = 'FOREIGN KEY'
;
-- SELECT @FOREIGN_KEY_my_foreign_key_ON_TABLE_my_table_EXISTS;
SET @statement := IF(
    @FOREIGN_KEY_my_foreign_key_ON_TABLE_my_table_EXISTS > 0,
    -- 'SELECT "info: foreign key exists."',
    'ALTER TABLE my_table DROP FOREIGN KEY my_foreign_key',
    'SELECT "info: foreign key does not exist."'
);
PREPARE statement FROM @statement;
EXECUTE statement;
1
automatix