Saya memiliki tabel story_category
di database saya dengan entri yang korup. Kueri berikutnya mengembalikan entri yang rusak:
SELECT *
FROM story_category
WHERE category_id NOT IN (
SELECT DISTINCT category.id
FROM category INNER JOIN
story_category ON category_id=category.id);
Saya mencoba menghapusnya:
DELETE FROM story_category
WHERE category_id NOT IN (
SELECT DISTINCT category.id
FROM category
INNER JOIN story_category ON category_id=category.id);
Tapi saya mendapatkan kesalahan selanjutnya:
# 1093 - Anda tidak dapat menentukan tabel target 'story_category' untuk pembaruan dalam klausa FROM
Bagaimana saya bisa mengatasi ini?
mysql
subquery
sql-delete
mysql-error-1093
Sergio del Amo
sumber
sumber
Jawaban:
Pembaruan: Jawaban ini mencakup klasifikasi kesalahan umum. Untuk jawaban yang lebih spesifik tentang cara terbaik menangani permintaan persis OP, silakan lihat jawaban lain untuk pertanyaan ini
Di MySQL, Anda tidak bisa mengubah tabel yang sama yang Anda gunakan di bagian SELECT.
Perilaku ini didokumentasikan di: http://dev.mysql.com/doc/refman/5.6/en/update.html
Mungkin Anda bisa bergabung dengan tabel itu sendiri
Jika logikanya cukup sederhana untuk membentuk kembali kueri, kehilangan subquery dan bergabung dengan tabel itu sendiri, menggunakan kriteria seleksi yang sesuai. Ini akan menyebabkan MySQL melihat tabel sebagai dua hal yang berbeda, memungkinkan perubahan destruktif untuk terus maju.
Atau, coba nempatkan subquery lebih dalam ke dalam dari klausa ...
Jika Anda benar-benar membutuhkan subquery, ada solusinya, tetapi jelek karena beberapa alasan, termasuk kinerja:
Subquery bersarang di klausa FROM membuat tabel sementara implisit , sehingga tidak dihitung sebagai tabel yang sama dengan yang Anda perbarui.
... tapi hati-hati dengan pengoptimal kueri
Namun, berhati-hatilah bahwa dari MySQL 5.7.6 dan seterusnya, pengoptimal dapat mengoptimalkan subquery, dan masih memberi Anda kesalahan. Untungnya,
optimizer_switch
variabel dapat digunakan untuk mematikan perilaku ini; meskipun saya tidak bisa merekomendasikan melakukan ini sebagai sesuatu yang lebih dari perbaikan jangka pendek, atau untuk tugas-tugas kecil satu kali.Terima kasih kepada Peter V. Mørch untuk saran ini di komentar.
Contoh teknik berasal dari Baron Schwartz, awalnya diterbitkan di Nabble , diparafrasekan dan diperluas di sini.
sumber
SET optimizer_switch = 'derived_merge=off';
:-(NexusRex memberikan solusi yang sangat baik untuk dihapus dengan bergabung dari tabel yang sama.
Jika kamu melakukan ini:
Anda akan mendapatkan kesalahan.
Tetapi jika Anda membungkus kondisinya dalam satu lagi pilih:
itu akan melakukan hal yang benar !!
Penjelasan: Pengoptimal kueri melakukan optimasi gabungan turunan untuk kueri pertama (yang menyebabkannya gagal dengan kesalahan), tetapi kueri kedua tidak memenuhi syarat untuk optimasi gabungan turunan . Oleh karena itu pengoptimal dipaksa untuk mengeksekusi subquery terlebih dahulu.
sumber
Di
inner join
dalam sub-kueri Anda tidak perlu. Sepertinya Anda ingin menghapus entri distory_category
manacategory_id
tidak ada dalamcategory
tabel.Melakukan hal ini:
Alih-alih itu:
sumber
DISTINCT
tidak perlu di sini - untuk kinerja yang lebih baik;).where in
di kolom ID, jadi Anda tidak perlu membuat subquery tabel utama.Baru-baru ini saya harus memperbarui catatan dalam tabel yang sama saya melakukannya seperti di bawah ini:
sumber
UPDATE skills SET type='Development' WHERE type='Programming';
? Ini sepertinya tidak menjawab pertanyaan awal.UPDATE skills SET type='Development' WHERE type='Programming';
. Saya tidak mengerti mengapa begitu banyak orang tidak berpikir tentang apa yang mereka lakukan ...sumber
UPDATE tbl AS a INNER JOIN tbl AS b ON .... SET a.col = b.col
- ini akan berfungsi sebagai alias berbeda untuk tabel yang sama digunakan di sini. Demikian pula dalam jawaban @ NexusRexSELECT
kueri pertama bertindak sebagai tabel turunan yangstory_category
digunakan untuk kedua kalinya. Jadi kesalahan yang disebutkan dalam OP seharusnya tidak terjadi di sini, kan?Jika Anda tidak bisa melakukannya
karena ini adalah meja yang sama, Anda dapat menipu dan melakukan:
[perbarui atau hapus atau apa pun]
sumber
Ini adalah apa yang saya lakukan untuk memperbarui nilai kolom Prioritas dengan 1 jika itu adalah = = 1 dalam sebuah tabel dan dalam klausa WHERE yang menggunakan subquery pada tabel yang sama untuk memastikan bahwa setidaknya satu baris berisi Prioritas = 1 (karena itu adalah kondisi yang akan diperiksa saat melakukan pembaruan):
Saya tahu itu agak jelek tapi itu berfungsi dengan baik.
sumber
Cara paling sederhana untuk melakukan ini adalah menggunakan tabel alias ketika Anda merujuk tabel kueri induk di dalam sub kueri.
Contoh:
Ubah ke:
sumber
Anda bisa memasukkan id baris yang diinginkan ke tabel temp dan kemudian menghapus semua baris yang ditemukan di tabel itu.
yang mungkin apa yang dimaksud @Cheekysoft dengan melakukannya dalam dua langkah.
sumber
Menurut Sintaks Mysql UPDATE ditautkan oleh @CheekySoft, ia mengatakan tepat di bagian bawah.
Saya kira Anda menghapus dari store_category sambil memilih dari dalam serikat.
sumber
Untuk permintaan spesifik yang ingin dicapai oleh OP, cara ideal dan paling efisien untuk melakukan ini adalah TIDAK menggunakan subquery sama sekali.
Berikut adalah
LEFT JOIN
versi dari dua kueri OP:Catatan:
DELETE s
membatasi operasi penghapusan kestory_category
tabel.Dokumentasi
sumber
UPDATE
pernyataan dan bergabung dengan sub-kueri. Memungkinkan Anda untuk melakukan yangLEFT JOIN ( SELECT ... )
bertentanganWHERE IN( SELECT ... )
, membuat implementasi bermanfaat di banyak kasus penggunaan.Jika sesuatu tidak berhasil, ketika datang melalui pintu depan, maka ambil pintu belakang:
Itu cepat. Semakin besar data, semakin baik.
sumber
Cobalah untuk menyimpan hasil pernyataan Pilih dalam variabel terpisah dan kemudian menggunakannya untuk menghapus kueri.
sumber
coba ini
sumber
bagaimana dengan kueri ini semoga membantu
sumber
DELETE story_category FROM ...
namun, sub-kueri yang digabung tidak diperlukan dalam konteks ini dan dapat dilakukan dengan menggunakanLEFT JOIN category AS cat ON cat.id = story_category.category_id WHERE cat.id IS NULL
, Perhatikan kriteria gabung dalam jawaban yang salah referensistory_category.id = cat.id
Sejauh menyangkut masalah, Anda ingin menghapus baris
story_category
yang tidak ada dicategory
.Inilah permintaan awal Anda untuk mengidentifikasi baris yang akan dihapus:
Menggabungkan
NOT IN
dengan subquery yangJOIN
merupakan tabel asli tampaknya berbelit-belit tidak perlu. Ini dapat diekspresikan dengan cara yang lebih langsung dengannot exists
dan subquery yang berkorelasi:Sekarang mudah untuk mengubahnya menjadi
delete
pernyataan:Pertanyaan ini akan berjalan pada versi MySQL apa pun, serta di sebagian besar database lain yang saya tahu.
Demo di DB Fiddle :
sumber