2010-10-12 14 views
18

Nel mio script creare per la mia banca dati creare uno script cercando qualcosa di simile:MySQL: Aggiungi vincolo se non esiste

CREATE TABLE IF NOT EXISTS `rabbits` 
(
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, 
    `name` VARCHAR(255) NOT NULL, 
    `main_page_id` INT UNSIGNED COMMENT 'What page is the main one', 
    PRIMARY KEY (`id`), 
    KEY `main_page_id` (`main_page_id`) 
) 
ENGINE=InnoDB; 

CREATE TABLE IF NOT EXISTS `rabbit_pages` 
(
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, 
    `rabbit_id` INT UNSIGNED NOT NULL, 
    `title` VARCHAR(255) NOT NULL, 
    `content` TEXT NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `rabbit_id` (`rabbit_id`), 
    CONSTRAINT `fk_rabbits_pages` FOREIGN KEY (`rabbit_id`) REFERENCES `rabbits` (`id`) 
) 
ENGINE=InnoDB; 

ALTER TABLE `rabbits` 
    ADD CONSTRAINT `fk_rabbits_main_page` FOREIGN KEY (`main_page_id`) REFERENCES `rabbit_pages` (`id`); 

Questo funziona bene la prima volta, ma se lo faccio funzionare di nuovo fallisce sull'ultima riga lì con "Duplica chiave su scrittura o aggiornamento".

C'è un modo per fare una specie di ADD CONSTRAINT IF NOT EXISTS o qualcosa del genere? Come posso fare con la query CREATE TABLE?

risposta

16

Interessante domanda. È possibile disabilitare le chiavi esterne prima di chiamare le istruzioni CREATE TABLE e attivarle in seguito. Questo vi permetterà di definire le chiavi esterne direttamente nel CREATE TABLE DDL:

Esempio: caso

SET FOREIGN_KEY_CHECKS = 0; 
Query OK, 0 rows affected (0.00 sec) 

CREATE TABLE IF NOT EXISTS `rabbits` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, 
    `name` VARCHAR(255) NOT NULL, 
    `main_page_id` INT UNSIGNED COMMENT 'What page is the main one', 
    PRIMARY KEY (`id`), 
    KEY `main_page_id` (`main_page_id`), 
    CONSTRAINT `fk_rabbits_main_page` FOREIGN KEY (`main_page_id`) REFERENCES `rabbit_pages` (`id`) 
) ENGINE=InnoDB; 
Query OK, 0 rows affected (0.04 sec) 

CREATE TABLE IF NOT EXISTS `rabbit_pages` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, 
    `rabbit_id` INT UNSIGNED NOT NULL, 
    `title` VARCHAR(255) NOT NULL, 
    `content` TEXT NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `rabbit_id` (`rabbit_id`), 
    CONSTRAINT `fk_rabbits_pages` FOREIGN KEY (`rabbit_id`) REFERENCES `rabbits` (`id`) 
) ENGINE=InnoDB; 
Query OK, 0 rows affected (0.16 sec) 

SET FOREIGN_KEY_CHECKS = 1; 
Query OK, 0 rows affected (0.00 sec) 

prova:

INSERT INTO rabbits (name, main_page_id) VALUES ('bobby', NULL); 
Query OK, 1 row affected (0.02 sec) 

INSERT INTO rabbit_pages (rabbit_id, title, content) VALUES (1, 'My Main Page', 'Hello'); 
Query OK, 1 row affected (0.00 sec) 

SELECT * FROM rabbits; 
+----+-------+--------------+ 
| id | name | main_page_id | 
+----+-------+--------------+ 
| 1 | bobby | NULL   | 
+----+-------+--------------+ 
1 row in set (0.00 sec) 

SELECT * FROM rabbit_pages; 
+----+-----------+--------------+---------+ 
| id | rabbit_id | title  | content | 
+----+-----------+--------------+---------+ 
| 1 |   1 | My Main Page | Hello | 
+----+-----------+--------------+---------+ 
1 row in set (0.00 sec) 

UPDATE rabbits SET main_page_id = 2 WHERE id = 1; 
ERROR 1452 (23000): A foreign key constraint fails 

UPDATE rabbits SET main_page_id = 1 WHERE id = 1; 
Query OK, 1 row affected (0.00 sec) 
Rows matched: 1 Changed: 1 Warnings: 0 

UPDATE rabbit_pages SET rabbit_id = 2 WHERE id = 1; 
ERROR 1452 (23000): A foreign key constraint fails 
+0

Hm, ho pensato che dovevo creare tabella A, create table B con B-> A e quindi aggiungere A-> B perché il vincolo fallirebbe se una tabella non esiste ancora ... strano ... lo proveremo al più presto: p – Svish

+0

@Svish: Lo farebbe, a meno che tu non abbia "SET FOREIGN_KEY_CHECKS = 0;" in alto. Questo è il trucco. Stiamo quindi riportando a '1' alla fine. –

+1

Fantastico. Funziona completamente: D – Svish

20

Il FOREIGN_KEY_CHECKS è un grande strumenti, ma se il vostro bisogno di sapere come fare senza perdere e ricreare le tabelle, è possibile utilizzare un'istruzione select per determinare se esiste la chiave esterna:

IF NOT EXISTS (SELECT NULL FROM information_schema.TABLE_CONSTRAINTS WHERE 
        CONSTRAINT_SCHEMA = DATABASE() AND 
        CONSTRAINT_NAME = 'fk_rabbits_main_page' AND 
        CONSTRAINT_TYPE = 'FOREIGN KEY') THEN 
    ALTER TABLE `rabbits` ADD CONSTRAINT `fk_rabbits_main_page` 
          FOREIGN KEY (`main_page_id`) 
          REFERENCES `rabbit_pages` (`id`); 
END IF 
+0

Questo è molto utile e difensivo mi piace –

+3

Questa soluzione sembra funzionare, ma genera il seguente errore (se lo si utilizza al posto di ALTER TABLE nell'istruzione SQL originale pubblicata da OP): '[ERROR in query 3] Hai un errore nella sintassi SQL; controlla il manuale corrispondente alla versione del tuo server MySQL per la sintassi corretta da usare vicino a "SE NON ESISTE (SELEZIONA NULL FROM information_schema.TABLE_CONSTRAINTS WHERE " alla riga 1 [ERRORE nella query 4] Hai un errore nella sintassi SQL; controlla il manuale che corrisponde alla tua versione del server MySQL per la sintassi corretta da usare vicino a "FINE IF" alla riga 1 " – jsdalton

+0

@jsdalton Penso che questa sintassi funzioni solo all'interno di una stored procedure – seanf

8

MariaDB supporta questa sintassi in 10.0.2 or later:

ALTER TABLE `rabbits` 
ADD CONSTRAINT `fk_rabbits_main_page` FOREIGN KEY IF NOT EXISTS 
(`main_page_id`) REFERENCES `rabbit_pages` (`id`); 
+0

Dang, solo mariadb. – Kzqai