Bagaimana cara mengubah tindakan referensial kunci asing? (tingkah laku)


102

Saya telah menyiapkan tabel yang berisi kolom dengan kunci asing, setel ke ON DELETE CASCADE(hapus anak ketika orang tua dihapus)

Apa perintah SQL untuk mengubahnya ON DELETE RESTRICT? (tidak dapat menghapus orang tua jika memiliki anak)

Jawaban:


170

Pertanyaan lama tetapi menambahkan jawaban sehingga seseorang bisa mendapatkan bantuan

Proses dua langkahnya:

Misalkan, a table1memiliki kunci asing dengan nama kolom fk_table2_id, dengan nama kendalafk_name dan table2disebut tabel dengan kunci t2( sesuatu seperti di bawah ini dalam diagram saya ).

   table1 [ fk_table2_id ] --> table2 [t2]

Langkah pertama , DROP CONSTRAINT lama: ( referensi )

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

batasan pemberitahuan dihapus, kolom tidak dihapus

Langkah kedua , TAMBAHKAN BATAS baru:

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

menambahkan kendala, kolom sudah ada

Contoh:

Saya memiliki UserDetailstabel yang merujuk ke Userstabel:

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

Langkah pertama:

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

Tahap kedua:

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)  

hasil:

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
Bukankah batasan yang Anda tambahkan harus ON DELETE BATAS seperti yang diminta oleh pertanyaan asli?
Noumenon

Ehm, apa itu "saat menghapus kaskade" dan mengapa itu perlu?
Lealo

3
@Noumenon RESTRICT adalah default sehingga Anda mendapatkannya saat tidak menentukan.
edruid

1
@Lealo "on delete cascade" berarti bahwa jika Anda menghapus baris dari tabel induk (Pengguna dalam hal ini) semua baris referensi dari tabel anak (UserDetails) juga dihapus.
edruid

1
terima kasih atas catatan "batasan pemberitahuan dihapus, kolom tidak dihapus", "batasan tambahan, kolom sudah ada", tebak itu berarti data praktis dipertahankan dan hanya skema yang berubah di sana
George Birbilis

21

Anda dapat melakukan ini dalam satu kueri jika Anda ingin mengubah namanya:

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

Ini berguna untuk meminimalkan waktu henti jika Anda memiliki meja besar.


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
membantu saya menemukan solusinya ALTER TABLE table_name ADD...ON DELETE RESTRICT
Moak

3
Tidak, fk_name adalah nama pembatas. Ini opsional untuk menyediakannya. Saya tidak yakin tapi mungkin Anda bisa mendapatkannya kembali menggunakan SHOW CREATE TABLE.
pascal

1
TENTANG PEMBATASAN CASCADE mungkin tidak dimaksudkan.
jgreep

5

Ingatlah bahwa MySQL menyimpan indeks sederhana pada kolom setelah menghapus kunci asing. Jadi, jika Anda perlu mengubah kolom 'referensi', Anda harus melakukannya dalam 3 langkah

  • jatuhkan FK asli
  • jatuhkan indeks (nama sebagai fk sebelumnya, menggunakan drop indexklausa)
  • buat FK baru

3

Anda cukup menggunakan satu kueri untuk mengatur semuanya: 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
ini hanya akan berfungsi jika Anda mengubah nama batasan (jika menggunakan nama yang dibuat secara otomatis mungkin akan berhasil, tebak MySQL selalu membuat yang unik)
George Birbilis

Kueri bekerja dengan pasti di MySQL / MariaDB. Kuncinya di sini adalah untuk
menghilangkan

1
sintaks kueri all-in-one tidak berfungsi untuk saya dengan MySQL ketika nama kendala eksplisit digunakan
George Birbilis

3

Saya memiliki banyak FK untuk diubah, jadi saya menulis sesuatu untuk membuat pernyataan untuk saya. Kupikir aku akan berbagi:

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
ini tidak akan berfungsi jika batasan ada di beberapa kolom. sql yang dihasilkan akan membuat batasan terpisah untuk setiap kolom
lampu

Semua FK saya berada di satu kolom, jadi saya tidak terlalu memikirkan kemungkinan itu, tapi pemikiran yang bagus
DavidSM
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.