dataiotech Labs
dbaguidedbaguideDBAdataxtoolsdataopsphere
Home/Hata Teşhis Kütüphanesi/mysql-1093-target-table-update-from-clause
MySQL
MySQL 5.7–8.4 LTSSorgu & Kısıtlar
6 dk okuma
ERROR 1093 (HY000): You can't specify target table for update in FROM clause

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.

İnceleyen:Principal Database Reliability Architect
Test Edilen Sürümler: MySQL 8.4 LTS, 8.0.40 & 5.7.44 (Docker 29.7)

Operasyonel Doğrulama & Güvenilirlik Standardı

Son Teknik İnceleme: 30 Ekim 2026
Test Edilen SürümlerMySQL 8.4 LTS, 8.0.40 & 5.7.44 (Debian Bookworm, Docker 29.7)
Gerekli YetkiHedef tabloda UPDATE ve alt sorguda SELECT yetkisi
Risk Seviyesi
LowGeçici tablo kopyası (temporary table) oluşturmak büyük tablolarda disk doluluğuna ve uzun süreli kilitlenmeye yol açar
Beklenen ÇıktıDerived table (türetilmiş tablo), JOIN veya CTE dönüşümüyle sorgunun 0 hata ile çalışması
Geri Dönüş (Rollback) Planı:UPDATE sorgusunu JOIN veya CTE sözdizimine dönüştürüp transaction içinde çalıştırma
MySQL 8.4 Docs: UPDATE Statement Limitations
İlk 60 Saniye Teşhis Protokolü:

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

plaintext
ERROR 1093 (HY000): You can't specify target table 'siparis' for update in FROM clause

Tipik tetikleyici SQL deseni:

sql
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. 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.
  2. 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:

sql
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 );
UYARI
MySQL 8.0 Optimizer Merge Tuzağı: MySQL 8.0 optimizer'ı bazen türetilmiş tabloları ana sorguyla birleştirmeye (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:

sql
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:

sql
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ı

Diğer Veritabanı Hata Teşhisleri

Kriz anında başvurabileceğiniz diğer doğrulanmış hata rehberleri.

Tüm Hatalar (50)