Wie ändere ich die referenzielle Aktion für Fremdschlüssel? (Verhalten)

102

Ich habe eine Tabelle eingerichtet, die eine Spalte mit einem Fremdschlüssel enthält, die auf ON DELETE CASCADE(Kind löschen, wenn Eltern gelöscht wird) gesetzt ist.

Was wäre der SQL-Befehl, um dies zu ändern ON DELETE RESTRICT? (Eltern können nicht gelöscht werden, wenn sie Kinder haben)

Moak
quelle

Antworten:

170

Alte Frage, aber Antwort hinzufügen, damit man Hilfe bekommen kann

Sein zweistufiger Prozess:

Nehmen wir an , ein table1eine hat Fremdschlüssel mit Spaltennamen fk_table2_id, mit Einschränkung Namen fk_nameund table2bezeichnet Tabelle mit Schlüssel t2( so etwas wie unten in meinem Diagramm ).

   table1 [ fk_table2_id ] --> table2 [t2]

Erster Schritt , DROP old CONSTRAINT: ( Referenz )

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

Hinweisbeschränkung wird gelöscht, Spalte wird nicht gelöscht

Zweiter Schritt , Neue Einschränkung hinzufügen:

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

Wenn Sie eine Einschränkung hinzufügen, ist die Spalte bereits vorhanden

Beispiel:

Ich habe eine UserDetailsTabelle bezieht sich auf UsersTabelle:

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`)
:
:

Erster Schritt:

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

Zweiter Schritt:

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)  

Ergebnis:

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
:
Grijesh Chauhan
quelle
2
Sollte die von Ihnen hinzugefügte Einschränkung nicht ON DELETE RESTRICT sein, wie in der ursprünglichen Frage gefordert?
Noumenon
Ähm, was ist "On Delete Cascade" und warum ist das notwendig?
Lealo
3
@Noumenon RESTRICT ist die Standardeinstellung, daher erhalten Sie diese, wenn Sie nicht angeben.
Edruid
1
@Lealo "on delete cascade" bedeutet, dass beim Löschen einer Zeile aus der übergeordneten Tabelle (in diesem Fall Benutzer) alle referenzierenden Zeilen aus der untergeordneten Tabelle (UserDetails) ebenfalls gelöscht werden.
Edruid
1
Vielen Dank für die Hinweise "Hinweis Einschränkung wird gelöscht, Spalte wird nicht gelöscht", "Einschränkung hinzufügen, Spalte ist bereits vorhanden", Vermutung, dass Daten praktisch erhalten bleiben und nur das Schema dort geändert wird
George Birbilis
21

Sie können dies in einer Abfrage tun, wenn Sie bereit sind, den Namen zu ändern:

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

Dies ist nützlich, um Ausfallzeiten zu minimieren, wenn Sie einen großen Tisch haben.

Romuald Brunet
quelle
11
ALTER TABLE DROP FOREIGN KEY fk_name;
ALTER TABLE ADD FOREIGN KEY fk_name(fk_cols)
            REFERENCES tbl_name(pk_names) ON DELETE RESTRICT;
Pascal
quelle
2
half mir, die Lösung zu finden ALTER TABLE table_name ADD...ON DELETE RESTRICT
Moak
3
Nein, fk_name ist der Einschränkungsname. Es ist optional, eine bereitzustellen. Ich bin nicht sicher, aber vielleicht können Sie es mit abrufen SHOW CREATE TABLE.
Pascal
1
ON CASCADE RESTRICT ist wahrscheinlich nicht vorgesehen.
Jgreep
5

Denken Sie daran, dass MySQL nach dem Löschen des Fremdschlüssels einen einfachen Index für eine Spalte führt. Wenn Sie also die Spalte "Referenzen" ändern müssen, sollten Sie dies in drei Schritten tun

  • Original FK fallen lassen
  • einen Index löschen (Namen wie vorheriges fk, using- drop indexKlausel)
  • neue FK erstellen
Vasiliy
quelle
3

Sie können einfach eine Abfrage verwenden, um alle zu regieren: 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

Stamster
quelle
1
Dies funktioniert nur, wenn Sie den Einschränkungsnamen ändern (wenn Sie einen automatisch generierten Namen verwenden, funktioniert dies wahrscheinlich, MySQL erstellt immer eindeutige Namen)
George Birbilis
Die Abfrage funktioniert sicher unter MySQL / MariaDB. Der Schlüssel hier ist, alte Einschränkung durch ihren Namen
Stamster
1
All-in-One-Abfragesyntax funktionierte bei mir mit MySQL nicht, wenn explizite Einschränkungsnamen verwendet wurden
George Birbilis
3

Ich musste ein paar FKs ändern, also schrieb ich etwas, um die Aussagen für mich zu machen. Ich dachte, ich würde teilen:

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'
DavidSM
quelle
1
Dies funktioniert nicht, wenn eine Einschränkung für mehrere Spalten gilt. Das generierte SQL erstellt separate Einschränkungen für jede Spalte
leuchtet am
Alle meine FKs befanden sich in einzelnen Spalten, daher dachte ich nicht so viel über diese Möglichkeit nach, sondern über gute Gedanken
DavidSM