MySQL Error 1093 — Aynı Tabloyu Neden Alt Sorguda Kullanamıyorum?
1093 hatasının nedeni, türetilmiş tablo çözümü, MySQL 8'de CTE ile yazımı ve geçici tablo kopyasının neden kötü bir çözüm olduğu.
Operasyonel Doğrulama & Güvenilirlik Standardı
Hata mesajı semptomdur, kök neden değildir. Sunucuyu yeniden başlatmadan veya rastgele ayar değiştirmeden önce aşağıdaki "Nedeni ayırt eden tek sorgu"yu çalıştırarak gerçek senaryoyu netleştirin.
▸Belirti
ERROR 1093 (HY000): You can't specify target table 'siparis' for update in FROM clauseTipik tetikleyici SQL deseni:
UPDATE siparis
SET durum = 'iptal'
WHERE id IN (
SELECT id FROM siparis WHERE tutar = 0 AND created_at < NOW() - INTERVAL 30 DAY
);Aynı tabloyu hem güncellemek (UPDATE) hem de alt sorguda filtreleme kriteri olarak okumak (SELECT) istiyorsunuz. PostgreSQL, Oracle ve SQL Server bu deseni sorunsuz kabul ederken, MySQL işlemi derleme aşamasında anında ERROR 1093 ile reddeder.
▸Neden Böyle Bir Kısıtlama Var?
Bu bir yetenek eksikliği değil, bilinçli bir veri tutarlılığı ve kilit koruma mimarisidir:
- 1İşlem Ortasında Değişen Küme: MySQL alt sorguyu güncelleme devam ederken satır satır değerlendirir. Güncellenmekte olan bir tablodan aynı anda alt sorgu ile veri okumak, okunan satır kümesinin işlemin tam ortasında mutasyona uğramasına yol açar.
- 2Replikasyon Belirsizliği: Statement-Based Replication (SBR) kullanılan ortamlarda, aynı ifadenin Replica üzerinde Master ile birebir aynı satırları güncelleyeceğinin garantisi verilemez. MySQL bu determinizm kaybını önlemek için ifadeyi baştan yasaklar.
▸Üç Temel Çözüm ve Kullanım Senaryoları
1. Türetilmiş Tablo (Derived Table) ile Maddileştirme (En Yaygın Çözüm)
İç içe bir SELECT katmanı ekleyerek MySQL optimizer'ını ara sonucu geçici bellekte maddileştirmeye (materialize) zorlayabilirsiniz:
UPDATE siparis
SET durum = 'iptal'
WHERE id IN (
SELECT id FROM (
SELECT id FROM siparis WHERE tutar = 0 AND created_at < NOW() - INTERVAL 30 DAY
) AS hedef
);derived_merge) çalışır ve 1093 hatası tekrar ortaya çıkabilir. Sürüm 8.0.22 ve sonrasında maddileştirmeyi zorunlu kılmak için /*+ NO_MERGE(hedef) */ optimizer ipucunu kullanın:
``sql
UPDATE siparis SET durum = 'iptal'
WHERE id IN (
SELECT /*+ NO_MERGE(hedef) */ id FROM (
SELECT id FROM siparis WHERE tutar = 0
) AS hedef
);
2. Multi-Table JOIN Sözdizimi (Önerilen En Temiz Çözüm)
JOIN sözdizimi hem sorgu planının öngörülebilirliği hem de kod okunabilirliği açısından üretim ortamlarında en sağlıklı yaklaşımdır:
UPDATE siparis s
JOIN (
SELECT id FROM siparis WHERE tutar = 0 AND created_at < NOW() - INTERVAL 30 DAY
) h ON h.id = s.id
SET s.durum = 'iptal';3. MySQL 8.0 Common Table Expressions (CTE)
MySQL 8.0+ kullanıyorsanız niyeti en açık biçimde ortaya koyan yöntem CTE sözdizimidir:
WITH hedef AS (
SELECT id FROM siparis WHERE tutar = 0 AND created_at < NOW() - INTERVAL 30 DAY
)
UPDATE siparis s
JOIN hedef h ON h.id = s.id
SET s.durum = 'iptal';▸Asla Yapılmaması Gereken: Fiziksel Geçici Tablo Kopyası
Sık yapılan acemi bir hata, "tabloyu CREATE TEMPORARY TABLE ile kopyalayıp oradan okumak"tır. Bu yöntem küçük veri setlerinde çalışıyor gibi görünse de büyük tablolarda felakettir:
- •Milyonlarca satırlık diske yazma yükü oluşturur.
- •Kopyalama süresince ana tablo üzerinde paylaşımlı kilit (shared lock) birikir.
- •Kopyalama anı ile asıl güncelleme anı arasında tabloya yeni satırlar eklenebilir veya silinebilir; veriler tutarsız hale gelir.
▸Benzer Ama Farklı Davranan SQL Desenleri
- •`DELETE` Sözdizimi:
DELETE FROM siparis WHERE id IN (SELECT id FROM siparis ...)aynı şekilde 1093 hatası verir; çözüm yukarıdaki JOIN deseniyle birebir aynıdır. - •`INSERT INTO ... SELECT`: MySQL aynı tablodan okuyup aynı tabloya ekleme yapılmasına (
INSERT INTO siparis SELECT ... FROM siparis) izin verir; hata vermez. - •Skaler Alt Sorgu Güncellemesi:
UPDATE siparis SET tutar = (SELECT MAX(tutar) FROM siparis)yine aynı 1093 kısıtlamasına takılır.
▸İlgili Hata Rehberleri & Hub Bağlantıları
- •MySQL Error 1451 Cannot Delete Parent Row (H-38) — Yabancı anahtar silme kısıtları
- •MySQL Error 1452 Foreign Key Constraint (H-14) — Ebeveyn satır eksikliği
- •MySQL Deadlock Found 1213 (H-05) — Eşzamanlı güncelleme kilitleri
- •MySQL Hub — MySQL performans ve sorgu optimizasyonu
Diğer Veritabanı Hata Teşhisleri
Kriz anında başvurabileceğiniz diğer doğrulanmış hata rehberleri.
MySQL ERROR 1045 Access denied: root Şifresi Sıfırlama Rehberi
MySQL 1045 hatasının dört nedeni, "using password: YES/NO" ayrımının anlamı ve kilitli kalınca --init-file ile güvenli şifre sıfırlama.
MySQL Deadlock ERROR 1213: Grafiği Okuma ve Kalıcı Önleme
MySQL 1213 deadlock hatasının nedeni, LATEST DETECTED DEADLOCK çıktısını okuma, gap lock kaynaklı kilitlenmeler ve uygulama tarafında retry tasarımı.
MySQL Lock wait timeout exceeded: Bloklayan İşlemi Bulma
1205 lock wait timeout hatasında bloklayan işlemi performance_schema ile bulma, KILL kararını verme ve kilidi kalıcı olarak azaltma yöntemleri.