Bagaimana cara memotong tabel dibatasi kunci asing?

648

Mengapa tidak TRUNCATE pada mygrouppekerjaan? Meskipun saya punya ON DELETE CASCADE SETsaya dapatkan:

GALAT 1701 (42000): Tidak dapat memotong tabel yang dirujuk dalam batasan kunci asing ( mytest. instance, CONSTRAINT instance_ibfk_1FOREIGN KEY ( GroupID) REFERENSI mytest. mygroup( ID))

drop database mytest;
create database mytest;
use mytest;

CREATE TABLE mygroup (
   ID    INT NOT NULL AUTO_INCREMENT PRIMARY KEY
) ENGINE=InnoDB;

CREATE TABLE instance (
   ID           INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
   GroupID      INT NOT NULL,
   DateTime     DATETIME DEFAULT NULL,

   FOREIGN KEY  (GroupID) REFERENCES mygroup(ID) ON DELETE CASCADE,
   UNIQUE(GroupID)
) ENGINE=InnoDB;
pengguna391986
sumber

Jawaban:

1001

Anda tidak bisa TRUNCATEtabel yang memiliki batasan FK diterapkan di atasnya ( TRUNCATEtidak sama dengan DELETE).

Untuk mengatasinya, gunakan salah satu dari solusi ini. Keduanya menghadirkan risiko merusak integritas data.

Pilihan 1:

  1. Hapus kendala
  2. Melakukan TRUNCATE
  3. Hapus secara manual baris yang sekarang memiliki referensi ke mana pun
  4. Buat kendala

Opsi 2: disarankan oleh user447951 dalam jawaban mereka

SET FOREIGN_KEY_CHECKS = 0; 
TRUNCATE table $table_name; 
SET FOREIGN_KEY_CHECKS = 1;
zerkms
sumber
46
@barjonah: sebenarnya, ini dapat merusak integritas data (lihat stackoverflow.com/questions/5452760/… ). Jadi, apa yang Anda sebut "cahaya" di dunia nyata dianggap sebagai praktik yang buruk. PS: terima kasih untuk downvote
zerkms
1
Berikut ini adalah cara yang sangat baik untuk menemukan kunci asing yatim (mengembalikan integritas data) http://stackoverflow.com/a/12085689/997776
SandorRacz
menonaktifkan kunci asing sebelum memotong juga merupakan cara yang baik, saya melakukannya dengan sukses dari sumber: stackoverflow.com/questions/8641703/...
Dung
2
@Dung menonaktifkan pemeriksaan kunci asing hanya diizinkan pada periode pengembangan. Itu merusak hubungan yang ada. Zerkms 100% benar tentang integritas data. Anda tidak dapat menonaktifkan pemeriksaan kunci asing pada basis data yang berfungsi kecuali Anda berencana untuk mengosongkannya sepenuhnya (atau setidaknya semua tabel terkait)
NoobishPro
1
@Kamlesh itu bukan solusi saya, saya menyarankan untuk tidak melakukannya dengan cara yang biadab.
zerkms
1308

Ya kamu bisa:

SET FOREIGN_KEY_CHECKS = 0;

TRUNCATE table1;
TRUNCATE table2;

SET FOREIGN_KEY_CHECKS = 1;

Dengan pernyataan ini, Anda berisiko membiarkan dalam baris ke dalam tabel Anda yang tidak mematuhi FOREIGN KEYkendala.

pengguna447951
sumber
30
apakah kita harus mengatur SET FOREIGN_KEY_CHECKS = 1; lagi sesudahnya?
vinc3m1
77
Tidak, tidak. Pengaturan hanya valid selama koneksi. Segera setelah Anda memutuskan sambungan, koneksi berikutnya akan mengaturnya kembali ke 1.
The Pellmeister
7
Ini tidak menerapkan acara 'HAPUS DIHAPUS' di tabel yang direferensikan, jadi ini bukan jawaban yang lengkap.
Omer Sabic
5
Jika menggunakan PHPMYADMIN, ini hanya berfungsi jika Anda menggunakan semua transaksi dalam jendela SQL yang sama (dipisahkan oleh a ;). Ini karena setiap panggilan SQL web baru akan mengatur ulang FOREIGN_KEY_CHECKSke 1.
Sablefoste
1
Berikut ini adalah cara yang sangat baik untuk menemukan kunci asing yatim (mengembalikan integritas data) jika Anda tertarik http://stackoverflow.com/a/12085689/997776
SandorRacz
173

Saya hanya akan melakukannya dengan:

DELETE FROM mytest.instance;
ALTER TABLE mytest.instance AUTO_INCREMENT = 1;
George Garchagudashvili
sumber
5
Pintar. Ketika Anda ingin menghapus semua catatan, Anda mungkin juga mengatur ulang kenaikan otomatis.
winkbrace
6
Ini jelas cara terbaik untuk melakukannya. Tidak ada risiko kehilangan kendala, cukup hapus saja. Perlu diperhatikan bahwa DELETEkinerjanya lebih lambat daripada TRUNCATE. Tetapi karena tindakan ini biasanya jarang dilakukan, ini tidak masalah.
phil294
Ini bagus jika hanya itu yang ingin Anda lakukan, tetapi DELETEdapat benar-benar brutal jika Anda memiliki terlalu banyak baris - karena itu mengenai log, sedangkan TRUNCATEhanya merobek data. Sangat tergantung pada use case.
Jeff
1
ketika saya menggunakan pernyataan hapus, ini melaporkan kesalahan 1175: Anda menggunakan mode pembaruan aman, tambahkan saja SET SQL_SAFE_UPDATES = 0; maka tidak apa
tyan
Saat menggunakan solusi ini, ia melaporkan error 1175: You are using safe update mode,...perubahan klausa penghapusan untuk DELETE FROM mydb.mytable where id != 0membuatnya sempurna.
Shihe Zhang
17

Anda dapat melakukan

DELETE FROM `mytable` WHERE `id` > 0
Ali Sadran
sumber
1
Saya mencobanya, kesalahan berikut muncul: Kode Kesalahan: 1142. Perintah DELETE ditolak untuk pengguna 'root' @ 'localhost' untuk tabel 'mytable'
AAEM
atau hanya HAPUS DARImytable
Miloslav Milo Janoušek
Ini tidak akan mengatur ulang kenaikan otomatis.
vivek_23
13

Sesuai dokumentasi mysql , TRUNCATE tidak dapat digunakan pada tabel dengan hubungan kunci asing. Tidak ada AFAIK alternatif lengkap.

Menjatuhkan contraint masih tidak meminta ON DELETE dan ON UPDATE. Satu-satunya solusi yang bisa saya pikirkan adalah ATM:

  • hapus semua baris, lepas kunci asing, potong, buat ulang kunci
  • hapus semua baris, setel ulang auto_increment (jika digunakan)

Tampaknya TRUNCATE di MySQL belum merupakan fitur yang lengkap (ini juga tidak memicu pemicu). Lihat komentar

Omer Sabic
sumber
7
Catatan tentang pendapat Anda tentang MySQL TRUNCATEtidak lengkap - truncate tidak seharusnya memanggil pemicu, dll. Jika ya, itu akan sama dengan DELETE! Ini agnostik baris, karenanya tidak dapat melakukan operasi terkait baris (seperti mengaktifkan pemicu atau memeriksa kunci asing). Ini bekerja dengan cara yang sama di Oracle dan Sql Server .
Simon MᶜKenzie
8

Mudah jika Anda menggunakan phpMyAdmin.

Hapus centang Enable foreign key checksopsi di bawah SQLtab dan jalankanTRUNCATE <TABLE_NAME>

masukkan deskripsi gambar di sini

Ajmal Salim
sumber
8

Meskipun pertanyaan ini diajukan, saya tidak tahu, tetapi sekarang jika Anda menggunakan phpMyAdmin, Anda cukup membuka basis data dan memilih tabel yang ingin Anda potong.

  • Di bagian bawah ada drop down dengan banyak pilihan. Buka dan pilih Emptyopsi di bawah tajuk Delete data or table.
  • Ini akan membawa Anda ke halaman berikutnya secara otomatis di mana ada opsi di kotak centang yang disebut Enable foreign key checks. Cukup batalkan pilihan dan tekan Yestombol dan tabel yang dipilih akan terpotong.

Mungkin secara internal menjalankan kueri yang disarankan dalam jawaban user447951 , tetapi sangat mudah digunakan dari antarmuka phpMyAdmin.

Rolen Koh
sumber
8

Diuji pada MYSQL Database

Solusi 1:

SET FOREIGN_KEY_CHECKS = 0;
TRUNCATE table1;

Solusi 2:

DELETE FROM table1;
ALTER TABLE table1 AUTO_INCREMENT = 1;
TRUNCATE table1;

Ini bekerja untuk saya. Saya harap, ini akan membantu Anda juga. Terima kasih telah mengajukan pertanyaan ini.

Kamlesh
sumber
6

Jawaban memang yang disediakan oleh zerkms , sebagaimana dinyatakan pada Opsi 1 :

Opsi 1 : yang tidak berisiko merusak integritas data:

  1. Hapus kendala
  2. Lakukan TRUNCATE
  3. Hapus secara manual baris yang sekarang memiliki referensi ke mana pun
  4. Buat kendala

Bagian yang sulit adalah Menghilangkan kendala , jadi saya ingin memberi tahu Anda caranya, jika seseorang perlu tahu bagaimana melakukan itu:

  1. Jalankan SHOW CREATE TABLE <Table Name>kueri untuk melihat siapa nama KUNCI ASING Anda (Bingkai merah pada gambar di bawah):

    masukkan deskripsi gambar di sini

  2. Lari ALTER TABLE <Table Name> DROP FOREIGN KEY <Foreign Key Name>. Ini akan menghapus batasan kunci asing.

  3. Jatuhkan Indeks yang terkait (melalui halaman struktur tabel), dan Anda selesai.

untuk membuat kembali kunci asing:

ALTER TABLE <Table Name>
ADD FOREIGN KEY (<Field Name>) REFERENCES <Foreign Table Name>(<Field Name>);
Pmpr
sumber
3

Cukup gunakan CASCADE

TRUNCATE "products" RESTART IDENTITY CASCADE;

Tapi bersiaplah untuk menghapus cascade)

Alexus1024
sumber
3
OP menandai MySQL. Walaupun ini valid di Postgres, itu tidak benar di MySQL.
Peter
1

Jika mesin database untuk tabel berbeda Anda akan mendapatkan kesalahan ini jadi ubah ke InnoDB

ALTER TABLE my_table ENGINE = InnoDB;
sajad abbasi
sumber
0

Mendapatkan status pemeriksaan kunci asing lama dan mode sql adalah cara terbaik untuk memotong / menjatuhkan tabel seperti yang dilakukan Mysql Workbench saat menyinkronkan model ke database.

SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;`
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES';

DROP TABLE TABLE_NAME;
TRUNCATE TABLE_NAME;

SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
Vijay Arun
sumber