Tidak dapat menghapus atau memperbarui baris induk: batasan kunci asing gagal

170

Ketika melakukan:

DELETE FROM `jobs` WHERE `job_id` =1 LIMIT 1 

Kesalahan:

#1451 - Cannot delete or update a parent row: a foreign key constraint fails 
(paymesomething.advertisers, CONSTRAINT advertisers_ibfk_1 FOREIGN KEY 
(advertiser_id) REFERENCES jobs (advertiser_id))

Ini meja saya:

CREATE TABLE IF NOT EXISTS `advertisers` (
  `advertiser_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `password` char(32) NOT NULL,
  `email` varchar(128) NOT NULL,
  `address` varchar(255) NOT NULL,
  `phone` varchar(255) NOT NULL,
  `fax` varchar(255) NOT NULL,
  `session_token` char(30) NOT NULL,
  PRIMARY KEY (`advertiser_id`),
  UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;


INSERT INTO `advertisers` (`advertiser_id`, `name`, `password`, `email`, `address`, `phone`, `fax`, `session_token`) VALUES
(1, 'TEST COMPANY', '', '', '', '', '', '');

CREATE TABLE IF NOT EXISTS `jobs` (
  `job_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `advertiser_id` int(11) unsigned NOT NULL,
  `name` varchar(255) NOT NULL,
  `shortdesc` varchar(255) NOT NULL,
  `longdesc` text NOT NULL,
  `address` varchar(255) NOT NULL,
  `time_added` int(11) NOT NULL,
  `active` tinyint(1) NOT NULL,
  `moderated` tinyint(1) NOT NULL,
  PRIMARY KEY (`job_id`),
  KEY `advertiser_id` (`advertiser_id`,`active`,`moderated`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;


INSERT INTO `jobs` (`job_id`, `advertiser_id`, `name`, `shortdesc`, `longdesc`, `address`, `active`, `moderated`) VALUES
(1, 1, 'TEST', 'TESTTEST', 'TESTTESTES', '', 0, 0);

ALTER TABLE `advertisers`
  ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`) REFERENCES `jobs` (`advertiser_id`);
steven
sumber

Jawaban:

108

Seperti, Anda harus menghapus baris dari tabel pengiklan sebelum Anda dapat menghapus baris dalam tabel pekerjaan yang dirujuk. Ini:

ALTER TABLE `advertisers`
  ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`) 
      REFERENCES `jobs` (`advertiser_id`);

... sebenarnya kebalikan dari apa yang seharusnya. Karena itu, berarti Anda harus memiliki catatan di tabel pekerjaan sebelum pengiklan. Jadi, Anda perlu menggunakan:

ALTER TABLE `jobs`
  ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`) 
      REFERENCES `advertisers` (`advertiser_id`);

Setelah Anda memperbaiki hubungan kunci asing, pernyataan penghapusan Anda akan berfungsi.

OMG Ponies
sumber
3
Pada baris pertama: bukankah menurut Anda seharusnya "itu merujuk" alih-alih "yang merujuknya"? Atau pernahkah saya salah paham bagaimana seharusnya istilah referensi berfungsi?
Abraham Philip
6
@AbrahamPhilip Saya memikirkan hal yang sama. pengiklan mereferensikan pekerjaan.
keyser
270

Cara sederhana adalah dengan menonaktifkan pemeriksaan kunci asing; lakukan perubahan lalu aktifkan kembali pemeriksaan kunci asing.

SET FOREIGN_KEY_CHECKS=0; -- to disable them
SET FOREIGN_KEY_CHECKS=1; -- to re-enable them
Alino Manzi
sumber
171
Ini bukan solusi untuk masalah ini, tetapi lebih tepatnya penyelesaian yang kotor yang mungkin tidak diinginkan.
madfriend
20
Dalam kasus saya: Saya baru saja menjalankan file SQL besar dan salah satu pernyataan terakhir gagal, jadi saya hanya ingin menghapus semua tabel, memperbaiki kesalahan sintaks, dan menjalankan kembali, membuat ini tepat apa yang saya cari.
ekerner
1
Jika Anda akan melakukan ini, mengapa tidak menghapus semua kendala?
Sablefoste
1
Ini berguna ketika melakukan sesuatu seperti:REPLACE INTO tab_with_constraint ...
Maciek Łoziński
5
Satu-satunya alasan untuk meningkatkan jawaban ini adalah jika Anda hanya ingin kode Anda berhenti berteriak pada Anda dan menempa lebih dalam spaghetti tanpa memahami kode yang Anda tulis. Alasan untuk memiliki kunci asing di tempat pertama adalah untuk menegakkan integritas referensial. Jika Anda perlu menonaktifkannya untuk membuat kode Anda tertutup, Anda mungkin ingin memikirkan kembali kunci asing Anda, daripada menonaktifkannya.
cytinus
38

Di bawah desain Anda saat ini (mungkin cacat), Anda harus menghapus baris dari tabel pengiklan sebelum Anda dapat menghapus baris di tabel pekerjaan yang dirujuk.

Atau, Anda bisa mengatur kunci asing Anda sehingga penghapusan di tabel induk menyebabkan baris dalam tabel anak dihapus secara otomatis. Ini disebut penghapusan cascading. Itu terlihat seperti ini:

ALTER TABLE `advertisers`
ADD CONSTRAINT `advertisers_ibfk_1`
FOREIGN KEY (`advertiser_id`) REFERENCES `jobs` (`advertiser_id`)
ON DELETE CASCADE;

Karena itu, seperti yang telah ditunjukkan orang lain, kunci asing Anda terasa seperti itu harus berbalik karena tabel pengiklan benar-benar berisi kunci utama dan tabel pekerjaan berisi kunci asing. Saya akan menulis ulang seperti ini:

ALTER TABLE `jobs`
ADD FOREIGN KEY (`advertiser_id`) REFERENCES `advertisers` (`advertiser_id`);

Dan penghapusan cascading tidak akan diperlukan.

Asaf
sumber
18

Jika Anda ingin menjatuhkan tabel, Anda harus menjalankan kueri berikut dalam satu langkah

SET FOREIGN_KEY_CHECKS = 0; DROP TABLE table_name;

Abin John
sumber
13

Saya mencoba solusi yang disebutkan oleh @Alino Manzi tetapi tidak berhasil bagi saya di tabel terkait WordPress menggunakan wpdb.

kemudian saya memodifikasi kode seperti di bawah ini dan berhasil

SET FOREIGN_KEY_CHECKS=OFF; //disabling foreign key

//run the queries which are giving foreign key errors

SET FOREIGN_KEY_CHECKS=ON; // enabling foreign key
Moh
sumber
6

Saya pikir kunci asing Anda terbalik. Mencoba:

ALTER TABLE 'jobs'
ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`) REFERENCES `advertisers` (`advertiser_id`)
Tom H
sumber
5

Jika ada lebih dari satu pekerjaan yang memiliki advertiser_id yang sama, maka kunci asing Anda seharusnya:

ALTER TABLE `jobs`
ADD CONSTRAINT `advertisers_ibfk_1` 
FOREIGN KEY (`advertiser_id`) 
REFERENCES `advertisers` (`advertiser_id`);

Kalau tidak (jika sebaliknya dalam kasus Anda), jika Anda ingin baris pengiklan dihapus secara otomatis jika baris dalam pekerjaan dihapus tambahkan opsi 'ON DELETE CASCADE' di akhir kunci asing Anda:

ALTER TABLE `advertisers`
ADD CONSTRAINT `advertisers_ibfk_1` 
FOREIGN KEY (`advertiser_id`) 
REFERENCES `jobs` (`advertiser_id`)
ON DELETE CASCADE;

Lihat batasan Kunci Asing

JADI Pengguna
sumber
3

Anda perlu menghapusnya berdasarkan pesanan. Ada ketergantungan pada tabel

Ran Adler
sumber
2

Saat Anda membuat database atau membuat tabel

Anda harus menambahkan baris itu di skrip atas, buat database atau tabel

SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=1;

Sekarang Anda ingin menghapus catatan dari tabel? maka Anda menulis sebagai

SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=1;
DELETE FROM `jobs` WHERE `job_id` =1 LIMIT 1

Semoga berhasil!

Quy Le
sumber
2

Bagaimana dengan alternatif ini yang telah saya gunakan: izinkan kunci asing menjadi NULL dan kemudian pilih ON DELETE SET NULL .

Secara pribadi saya lebih suka menggunakan " ON UPDATE CASCADE " serta " ON DELETE SET NULL " untuk menghindari komplikasi yang tidak perlu, tetapi pada pengaturan Anda, Anda mungkin menginginkan pendekatan yang berbeda. Selain itu, NULL'ing nilai kunci asing dapat menyebabkan komplikasi karena Anda tidak akan tahu apa yang sebenarnya terjadi di sana. Jadi perubahan ini harus terkait erat dengan cara kerja kode aplikasi Anda.

Semoga ini membantu.

Marius Cucuruz
sumber
2

Saya punya masalah dalam migrasi laravel juga
urutan drop table dalam metode () tidak masalah

Schema::dropIfExists('groups');
Schema::dropIfExists('contact');

mungkin tidak berfungsi, tetapi jika Anda mengubah urutannya, itu berfungsi.

Schema::dropIfExists('contact');
Schema::dropIfExists('groups');
Amin
sumber
1

jika Anda perlu mendukung klien sesegera mungkin, dan tidak memiliki akses ke

FOREIGN_KEY_CHECKS

sehingga integritas data dapat dinonaktifkan:

1) hapus kunci asing

ALTER TABLE `advertisers` 
DROP FOREIGN KEY `advertisers_ibfk_1`;

2) aktifkan operasi penghapusan Anda melalui sql atau api

3) tambahkan kunci asing kembali ke skema

ALTER TABLE `advertisers`
  ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`) REFERENCES `jobs` (`advertiser_id`);

namun, ini merupakan hot-fix, jadi ini adalah risiko Anda sendiri, karena kelemahan utama dari pendekatan semacam itu adalah diperlukan setelah itu untuk menjaga integritas data secara manual.

Oleksii Kyslytsyn
sumber
0

Anda bisa membuat pemicu untuk menghapus baris yang direferensikan sebelum menghapus pekerjaan.

    DELIMITER $$
    CREATE TRIGGER before_jobs_delete 
        BEFORE DELETE ON jobs
        FOR EACH ROW 
    BEGIN
        delete from advertisers where advertiser_id=OLD.advertiser_id;
    END$$
    DELIMITER ;
Patch92
sumber
0

Masalah utama dengan erorr ini Error Code: 1451. Cannot delete or update a parent row: a foreign key constraint failsadalah ia tidak memberi tahu Anda tabel mana yang berisi kegagalan FK, sehingga sulit untuk menyelesaikan konflik.

Jika Anda menggunakan MySQL atau yang serupa, saya menemukan bahwa Anda dapat membuat diagram ER untuk database Anda, maka Anda dapat meninjau dan menghapus konflik yang memicu kesalahan dengan aman.

  1. Gunakan meja kerja MySQL
  2. Klik pada Database -> Reverse Engineering
  3. Pilih yang benar connection
  4. Selanjutnya sampai akhir, ingatlah untuk memilih database& tablesyang perlu diperiksa
  5. Sekarang Anda memiliki diagram ER, Anda dapat melihat tabel mana yang memiliki konflik FK
Ng Sek Long
sumber
0

Pada dasarnya, Alasan di balik jenis kesalahan ini adalah pada akhirnya Anda mencoba untuk menghapus tupple yang memiliki kunci utama (tabel akar) & bahwa kunci utama digunakan dalam tabel anak sebagai kunci asing. Dalam skenario ini untuk menghapus data tabel induk Anda harus menghapus data tabel anak (di mana kunci asing digunakan). Terima kasih

Kishan99
sumber
0

Ini terjadi pada saya juga dan karena ketergantungan dan referensi dari tabel lain, saya tidak bisa menghapus entri. Apa yang saya lakukan adalah menambahkan kolom hapus (dari tipe boolean) ke tabel. Nilai di bidang itu menunjukkan apakah item ditandai untuk dihapus atau tidak. Jika ditandai untuk dihapus, jangan mengambil / menggunakan; jika tidak, gunakan itu.

Tariq Kamal
sumber
-1

Mungkin Anda harus mencoba ON DELETE CASCADE


sumber
34
Secara buta menambahkan cascading delete (yang akan menghancurkan data) tanpa memahami masalahnya hanyalah hal terburuk yang bisa dilakukan seseorang.
Tom H