Come modificare l'azione referenziale della chiave esterna? (comportamento)


102

Ho impostato una tabella che contiene una colonna con una chiave esterna, impostata su ON DELETE CASCADE(elimina figlio quando il genitore viene eliminato)

Quale sarebbe il comando SQL per cambiarlo ON DELETE RESTRICT? (non è possibile eliminare il genitore se ha figli)

Risposte:


170

Vecchia domanda ma aggiunta di risposta in modo da poter ottenere aiuto

Il suo processo in due fasi:

Supponiamo che a table1abbia una chiave esterna con il nome della colonna fk_table2_id, con il nome del vincolofk_name e table2si riferisca alla tabella con la chiave t2( qualcosa come di seguito nel mio diagramma ).

   table1 [ fk_table2_id ] --> table2 [t2]

Primo passo , DROP old CONSTRAINT: ( riferimento )

ALTER TABLE `table1` 
DROP FOREIGN KEY `fk_name`;  

il vincolo di avviso viene eliminato, la colonna non viene eliminata

Secondo passaggio , AGGIUNGI nuovo VINCOLO:

ALTER TABLE `table1`  
ADD CONSTRAINT `fk_name` 
    FOREIGN KEY (`fk_table2_id`) REFERENCES `table2` (`t2`) ON DELETE CASCADE;  

aggiungendo vincolo, la colonna è già presente

Esempio:

Ho una UserDetailstabella si riferisce alla Userstabella:

mysql> SHOW CREATE TABLE UserDetails;
:
:
 `User_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`Detail_id`),
  KEY `FK_User_id` (`User_id`),
  CONSTRAINT `FK_User_id` FOREIGN KEY (`User_id`) REFERENCES `Users` (`User_id`)
:
:

Primo passo:

mysql> ALTER TABLE `UserDetails` DROP FOREIGN KEY `FK_User_id`;
Query OK, 1 row affected (0.07 sec)  

Secondo passo:

mysql> ALTER TABLE `UserDetails` ADD CONSTRAINT `FK_User_id` 
    -> FOREIGN KEY (`User_id`) REFERENCES `Users` (`User_id`) ON DELETE CASCADE;
Query OK, 1 row affected (0.02 sec)  

risultato:

mysql> SHOW CREATE TABLE UserDetails;
:
:
`User_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`Detail_id`),
  KEY `FK_User_id` (`User_id`),
  CONSTRAINT `FK_User_id` FOREIGN KEY (`User_id`) REFERENCES 
                                       `Users` (`User_id`) ON DELETE CASCADE
:

2
Il vincolo che aggiungi non dovrebbe essere ON DELETE RESTRICT come richiesto dalla domanda originale?
Noumenon

Ehm, cos'è "on delete cascade" e perché è necessario?
Lealo

3
@Noumenon RESTRICT è il valore predefinito, quindi lo ottieni quando non lo specifichi.
edruid

1
@Lealo "on delete cascade" significa che se si elimina una riga dalla tabella padre (Users in questo caso) vengono eliminate anche tutte le righe di riferimento dalla tabella figlio (UserDetails).
edruid

1
grazie per le note "il vincolo di avviso viene eliminato, la colonna non viene eliminata", "aggiunta di vincolo, la colonna è già presente", suppongo che ciò significhi che i dati sono praticamente conservati e solo lo schema cambia lì
George Birbilis

21

Puoi farlo in una query se sei disposto a cambiarne il nome:

ALTER TABLE table_name
  DROP FOREIGN KEY `fk_name`,
  ADD CONSTRAINT `fk_name2` FOREIGN KEY (`remote_id`)
    REFERENCES `other_table` (`id`)
    ON DELETE CASCADE;

Ciò è utile per ridurre al minimo i tempi di inattività se si dispone di una tabella di grandi dimensioni.


12
ALTER TABLE DROP FOREIGN KEY fk_name;
ALTER TABLE ADD FOREIGN KEY fk_name(fk_cols)
            REFERENCES tbl_name(pk_names) ON DELETE RESTRICT;

2
mi ha aiutato a trovare la soluzione ALTER TABLE table_name ADD...ON DELETE RESTRICT
Moak

3
No, fk_name è il nome del vincolo. È facoltativo fornirne uno. Non ne sono sicuro, ma forse puoi recuperarlo usando SHOW CREATE TABLE.
Pascal

1
ON CASCADE RESTRICT probabilmente non è previsto.
jgreep

5

Ricorda che MySQL mantiene un semplice indice su una colonna dopo aver eliminato la chiave esterna. Quindi, se hai bisogno di cambiare la colonna "riferimenti" dovresti farlo in 3 passaggi

  • goccia originale FK
  • rilascia un indice (nomi come fk precedente, utilizzando la drop indexclausola)
  • creare un nuovo FK

3

Puoi semplicemente utilizzare una query per regolarli tutti: ALTER TABLE products DROP FOREIGN KEY oldConstraintName, ADD FOREIGN KEY (product_id, category_id) REFERENCES externalTableName (foreign_key_name, another_one_makes_composite_key) ON DELETE CASCADE ON UPDATE CASCADE


1
funzionerà solo se modifichi il nome del vincolo (se usi un nome generato automaticamente probabilmente funzionerà, immagino che MySQL ne crei sempre di unici)
George Birbilis

La query funziona di sicuro su MySQL / MariaDB. La chiave qui è eliminare il vecchio vincolo con il suo nome, che viene fatto alla riga 2.
stamster

1
la sintassi della query all-in-one non ha funzionato per me con MySQL quando sono stati utilizzati nomi di vincoli espliciti
George Birbilis

3

Avevo un sacco di FK da modificare, quindi ho scritto qualcosa per fare le dichiarazioni per me. Ho pensato di condividere:

SELECT

CONCAT('ALTER TABLE `' ,rc.TABLE_NAME,
    '` DROP FOREIGN KEY `' ,rc.CONSTRAINT_NAME,'`;')
, CONCAT('ALTER TABLE `' ,rc.TABLE_NAME,
    '` ADD CONSTRAINT `' ,rc.CONSTRAINT_NAME ,'` FOREIGN KEY (`',kcu.COLUMN_NAME,
    '`) REFERENCES `',kcu.REFERENCED_TABLE_NAME,'` (`',kcu.REFERENCED_COLUMN_NAME,'`) ON DELETE CASCADE;')

FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
LEFT OUTER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu
    ON kcu.TABLE_SCHEMA = rc.CONSTRAINT_SCHEMA
    AND kcu.CONSTRAINT_NAME = rc.CONSTRAINT_NAME
WHERE DELETE_RULE = 'NO ACTION'
AND rc.CONSTRAINT_SCHEMA = 'foo'

1
questo non funzionerà se un vincolo è su più colonne. lo sql generato creerà vincoli separati per ogni colonna
luci

Tutti i miei FK erano su colonne singole, quindi non stavo pensando tanto a questa possibilità, ma un buon pensiero
DavidSM
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.