mysql delete dalam mode aman

92

Saya memiliki instruktur tabel dan saya ingin menghapus catatan yang memiliki gaji dalam kisaran Cara yang intuitif seperti ini:

delete from instructor where salary between 13000 and 15000;

Namun, dalam mode aman, saya tidak dapat menghapus rekaman tanpa memberikan kunci utama (ID).

Jadi saya menulis sql berikut:

delete from instructor where ID in (select ID from instructor where salary between 13000 and 15000);

Namun, ada kesalahan:

You can't specify target table 'instructor' for update in FROM clause

Saya bingung karena saat saya menulis

select * from instructor where ID in (select ID from instructor where salary between 13000 and 15000);

itu tidak menghasilkan kesalahan.

Pertanyaanku adalah:

  1. apa sebenarnya arti pesan kesalahan ini dan mengapa kode saya salah?
  2. bagaimana cara menulis ulang kode ini agar berfungsi dalam mode aman?

Terima kasih!

roland luo
sumber
apakah Anda ingin tetap mengaktifkan mode aman? dan apakah Anda menggunakan meja kerja mySql?
wribit
jawaban atas kedua pertanyaan Anda adalah ya. Dan saya terkejut bahwa ketika saya menggunakan jdbc untuk menghapus record di database mysql tanpa PK, itu tidak menghasilkan kesalahan. Jadi mode aman hanya untuk meja kerja mysql?
roland luo
1
tidak - Saya bertanya karena jika Anda ingin mematikannya di meja kerja mySQL, saya bisa memberi tahu Anda caranya. Secara pribadi saya mengatasinya ... harus memiliki ID adalah keamanan yang bagus - tetapi dari
segi

Jawaban:

233

Mencari-cari di Google, jawaban yang populer tampaknya "matikan saja mode aman" :

SET SQL_SAFE_UPDATES = 0;
DELETE FROM instructor WHERE salary BETWEEN 13000 AND 15000;
SET SQL_SAFE_UPDATES = 1;

Jika saya jujur, saya tidak bisa mengatakan saya pernah membuat kebiasaan berlari dalam mode aman. Namun, saya tidak sepenuhnya nyaman dengan jawaban ini karena ini hanya mengasumsikan Anda harus mengubah konfigurasi database Anda setiap kali Anda mengalami masalah.

Jadi, kueri kedua Anda lebih dekat ke tanda, tetapi mengalami masalah lain: MySQL menerapkan beberapa batasan pada subkueri, dan salah satunya adalah Anda tidak dapat mengubah tabel saat memilihnya di subkueri.

Mengutip dari manual MySQL, Batasan pada Subqueries :

Secara umum, Anda tidak dapat mengubah tabel dan memilih dari tabel yang sama di subkueri. Misalnya, batasan ini berlaku untuk pernyataan dengan bentuk berikut:

DELETE FROM t WHERE ... (SELECT ... FROM t ...);
UPDATE t ... WHERE col = (SELECT ... FROM t ...);
{INSERT|REPLACE} INTO t (SELECT ... FROM t ...);

Pengecualian: Larangan sebelumnya tidak berlaku jika Anda menggunakan subkueri untuk tabel yang diubah di klausa FROM. Contoh:

UPDATE t ... WHERE col = (SELECT * FROM (SELECT ... FROM t...) AS _t ...);

Di sini hasil dari subquery dalam klausa FROM disimpan sebagai tabel sementara, sehingga baris yang relevan di t telah dipilih pada saat pembaruan ke t berlangsung.

Bagian terakhir itu adalah jawaban Anda. Pilih ID target di tabel sementara, lalu hapus dengan mereferensikan ID di tabel itu:

DELETE FROM instructor WHERE id IN (
  SELECT temp.id FROM (
    SELECT id FROM instructor WHERE salary BETWEEN 13000 AND 15000
  ) AS temp
);

Demo SQLFiddle .

rutter
sumber
6
Terima kasih atas penjelasan Anda! Namun, saya mencoba kode Anda di meja kerja mysql dan masih mengatakan "Anda menggunakan mode pembaruan aman dan Anda mencoba memperbarui tabel tanpa WHERE yang menggunakan kolom KUNCI".
roland luo
Itu tidak terduga. Apakah kunci utama Anda dengan nama yang berbeda? Saya perhatikan pertanyaan Anda tampaknya menunjukkan namanya ID, sementara jawaban saya menggunakan id.
rutter
Ya, saya mengubahnya menjadi ID dan tidak berhasil. Saya mencoba menghapus dari instruktur di mana ID = '1' dan berfungsi sehingga ID adalah kunci utama
roland luo
1
@rolandluo Saya tahu ini sudah lama, tapi saya ingin tahu apakah Anda pernah menemukan solusi. Jelas metode ini berhasil dalam keadaan lain, jadi saya bertanya-tanya mengapa kasus Anda berbeda. Sesuatu yang spesifik untuk server atau versi Anda, mungkin?
rutter
19

Anda dapat mengelabui MySQL dengan berpikir bahwa Anda sebenarnya menentukan kolom kunci utama. Ini memungkinkan Anda untuk "menimpa" mode aman.

Dengan asumsi Anda memiliki tabel dengan kunci utama numerik yang bertambah otomatis, Anda dapat melakukan hal berikut:

DELETE FROM tbl WHERE id <> 0
Hugo Zink
sumber
12

Mematikan mode aman di meja kerja Mysql 6.3.4.0

Menu edit => Preferensi => Editor SQL: Bagian lain: klik "Pembaruan aman" ... untuk menghapus centang opsi

Preferensi Meja Kerja

Peter B
sumber
2
"bagaimana cara menulis ulang kode ini agar berfungsi dalam mode aman ?" ==> Jawaban Anda memberi tahu cara menonaktifkan mode aman;)
ByteHamster
2
Maaf, saya benar-benar salah paham dengan pertanyaan itu. Saya menemukan topik ini ketika saya tidak dapat menghapus dari tabel dengan meja kerja Mysql, dan ada pertanyaan serupa dalam komentar dengan meja kerja mysql, tetapi saya tidak dapat membuat komentar. Saya pikir, ini akan menjadi tempat yang baik untuk menulis ini di sini untuk referensi di masa mendatang ...
Peter B
0

Saya memiliki solusi yang jauh lebih sederhana, ini berhasil untuk saya; ini juga merupakan solusi tetapi mungkin dapat digunakan dan Anda tidak perlu mengubah pengaturan Anda. Saya berasumsi Anda dapat menggunakan nilai yang tidak akan pernah ada, lalu Anda menggunakannya pada klausa WHERE Anda

HAPUS DARI MyTable WHERE MyField IS_NOT_EQUAL AnyValueNoItemOnMyFieldWillEverHave

Saya juga tidak terlalu menyukai solusi itu, itulah mengapa saya ada di sini, tetapi berhasil dan tampaknya lebih baik daripada yang telah dijawab

Joaq
sumber