SQL foreign key hatası, child tablodaki bir değerin parent tabloda karşılık gelen kaydı bulamadığını veya ilişki kuralını ihlal ettiğini gösterir. Örneğin orders.customer_id değeri, customers.id sütununda bulunmuyorsa veritabanı bu siparişi eklemeyi ya da mevcut kaydı güncellemeyi reddeder.
Bu hata çoğunlukla constraint'i kaldırmayı değil; yanlış ID'yi, eksik parent kaydını, işlem sırasını veya ilişki tasarımını düzeltmeyi gerektirir. Hata mesajının biçimi ve kullanılan terminoloji veri tabanı motoruna göre değişebilir; bu nedenle mesajı yalnızca metin olarak değil, hangi tablo ve kolonların ilişki kurduğunu inceleyerek yorumlamak gerekir.
Foreign Key Hatası Neyi İfade Eder?
Foreign key, bir tablodaki değerin başka bir tablodaki geçerli bir kayda bağlanmasını sağlayan ilişkisel veri tabanı kuralıdır. Bağlantı kurulan tablo genellikle parent tablo, bu bağlantıyı taşıyan tablo ise child tablo olarak adlandırılır.
customers tablosunda müşterilerin kimlikleri tutulurken orders tablosu siparişleri tutabilir. Her siparişin hangi müşteriye ait olduğunu göstermek için orders.customer_id sütunu kullanılır:
customers.id -> orders.customer_id
Bu okun anlamı, orders.customer_id içinde yazan değerin customers.id içinde bulunması gerektiğidir. Örneğin customers tablosunda id = 7 olan bir müşteri varsa, orders.customer_id = 7 geçerli bir ilişkidir. Ancak parent tabloda 7 numaralı müşteri yoksa, bu değeri taşıyan siparişin eklenmesi veri bütünlüğünü bozabilir.
| Kavram | Görevi | Örnek |
|---|---|---|
| Parent tablo | Referans verilen ana kayıtları tutar | customers |
| Child tablo | Parent kayda bağlı kayıtları tutar | orders |
| Primary key | Parent kaydı benzersiz biçimde tanımlar | customers.id |
| Foreign key | Child kaydı parent kayda bağlar | orders.customer_id |
Bir INSERT işlemi sırasında yazılan foreign key değeri parent tabloda bulunmuyorsa hata oluşur. Benzer şekilde UPDATE işlemiyle mevcut bir customer_id değeri olmayan bir ID ile değiştirilirse aynı ilişki kuralı yeniden kontrol edilir. Bazı motorlarda mesaj içinde “foreign key constraint failed”, bazılarında ise constraint adı, tablo adı veya ihlal edilen anahtar bilgisi görülebilir.
Bu ilişkiyi anlamak, yalnızca SQL sözdizimini bilmekten daha fazlasını gerektirir. Önce hangi tablonun ana kayıtları tuttuğunu, sonra child tablonun hangi kolonla bu kayda bağlandığını düşünmek gerekir. İlişkisel düşünme becerinizi geliştirmek için algoritmik düşünme ve problem çözme becerilerinizi ölçebileceğiniz bilgi testi de yararlı bir başlangıç olabilir.
Foreign key hatası, veritabanının beklenmeyen veya anlamsız bir ilişkiyi engellediğini bildirir. Bu yüzden ilk çözüm olarak constraint'i devre dışı bırakmak ya da kaldırmak doğru değildir. Böyle bir yaklaşım, hatayı gizleyerek parent kaydı olmayan siparişlerin, raporlarda bozuk ilişkilerin ve ileride temizlenmesi zor verilerin oluşmasına yol açabilir.
customers ve orders Örneğiyle Hatalı INSERT Nasıl Teşhis Edilir?

Aşağıdaki örnekte önce tablolar oluşturulur, ardından bir müşteri eklenir. Daha sonra mevcut olmayan customer_id değeriyle hatalı bir sipariş eklenmeye çalışılır:
CREATE TABLE customers (
id INTEGER PRIMARY KEY,
name VARCHAR(100) NOT NULL
);
CREATE TABLE orders (
id INTEGER PRIMARY KEY,
customer_id INTEGER NOT NULL,
amount DECIMAL(10, 2),
FOREIGN KEY (customer_id) REFERENCES customers(id)
);
INSERT INTO customers (id, name) VALUES (1, 'Ayşe');
INSERT INTO orders (id, customer_id, amount) VALUES (101, 99, 250.00);
SELECT id, name FROM customers WHERE id = 99;
Hata, son INSERT satırında oluşur. Çünkü bu satırda orders.customer_id için 99 değeri verilmiştir; ancak hemen ardından yapılan SELECT sorgusunun sonuç döndürmemesi, customers.id = 99 olan parent kaydın bulunmadığını gösterir.
Teşhis akışı şu şekilde kurulmalıdır:
- Uygulamadan veya sorgudan gelen
customer_iddeğerini belirleyin. SELECT id, name FROM customers WHERE id = ...sorgusuyla parent kaydı doğrulayın.- Sonuç yoksa önce doğru müşteriyi ekleyin veya uygulamadan gelen ID'nin neden yanlış olduğunu düzeltin.
- Parent kayıt doğrulandıktan sonra child kaydı, yani siparişi ekleyin.
Doğru işlem sırası kısaca parent INSERT → parent SELECT/doğrulama → child INSERT şeklindedir:
INSERT INTO customers (id, name)
VALUES (2, 'Mehmet');
SELECT id, name
FROM customers
WHERE id = 2;
INSERT INTO orders (id, customer_id, amount)
VALUES (102, 2, 180.00);
Bu akışta ikinci sorgu id = 2 olan müşteriyi döndürür ve son INSERT geçerli bir parent kayda bağlandığı için başarılı olur. Gerçek projelerde otomatik ID üretimi, tablo oluşturma sözdizimi ve foreign key tanımlama biçimi kullanılan veri tabanı motoruna göre değişebilir. Bu nedenle çalıştırmadan önce hedef motorun kendi SQL sözdizimiyle karşılaştırma yapılmalıdır.
Bir video eğitimde SQL sorgularını çalıştırarak ilerlemek isteyen öğrenciler, asenkron yazılım video eğitimleri üzerinden kendi hızlarına uygun tekrar düzeni oluşturabilir.
Foreign Key Hatasının Beş Yaygın Kök Nedeni

Bir foreign key hatasını yalnızca “ID bulunamadı” şeklinde okumak eksik olur. Hatanın kaynağı; parent tablodaki veri, kolon tanımı, işlem sırası, NULL kullanımı veya parent kayıt üzerinde yapılan silme-güncelleme işlemi olabilir. Aşağıdaki beş kontrol, hatayı belirti üzerinden değil, kök neden üzerinden incelemenizi sağlar.
1. Parent Tabloda Olmayan ID
En yaygın neden, orders.customer_id değerinin customers.id içinde bulunmamasıdır. Örneğin 25 numaralı müşteri yokken siparişi doğrudan bu ID ile eklemek, child kaydının sahipsiz kalmasına yol açar.
SELECT id, name
FROM customers
WHERE id = 25;
INSERT INTO orders (customer_id, product_name)
VALUES (25, 'Klavye');
İlk sorgu satır döndürmüyorsa önce iş kuralına göre müşteriyi oluşturmalı veya sipariş işlemini durdurmalısınız. Rastgele bir ID ile tekrar denemek veri bütünlüğü sorununu çözmez.
2. Yanlış Kolon Eşleştirmesi veya Anahtar Uyumsuzluğu
Foreign key tanımı doğru tabloya işaret ediyor gibi görünse bile yanlış kolon eşleştirmesi hataya neden olabilir. orders.customer_id alanının müşteri numarası yerine e-posta, kullanıcı adı veya başka bir alanla ilişkilendirilmesi buna örnektir. Ayrıca veri tipi, uzunluk, işaretsiz/signed sayı kullanımı ya da parent anahtarın benzersiz olmaması motorun kurallarına takılabilir.
Önce tablo şemasını inceleyin. MySQL için SHOW CREATE TABLE customers; ve SHOW CREATE TABLE orders;; PostgreSQL için d customers ve d orders gibi motorunuza uygun araçları kullanın. Kontrol edilmesi gerekenler şunlardır:
- Foreign key hangi child kolonunu gösteriyor?
REFERENCEShangi parent tablo ve kolona bağlı?- İki kolonun anlamı ve veri tipi uyumlu mu?
- Parent tarafındaki anahtar gerçekten uygun bir aday anahtar mı?
3. Child Kaydının Parent Kayıttan Önce Eklenmesi
Bir transaction içinde önce sipariş, sonra müşteri eklenirse sipariş anında doğrulanacak parent kaydını bulamaz. Bu nedenle işlem akışını parent önce, child sonra olacak şekilde inceleyin.
BEGIN;
INSERT INTO customers (id, name)
VALUES (25, 'Ayşe Yılmaz');
INSERT INTO orders (customer_id, product_name)
VALUES (25, 'Klavye');
COMMIT;
Uygulama kodunda transaction adımlarını, otomatik ID üretimini ve kullanılan parametreyi birlikte kontrol edin. Parent kaydı başka bir transaction içinde oluşturuluyorsa commit zamanlaması da önem kazanabilir.
4. NULL Değerinin Constraint ve Kolon Tanımıyla İlişkisi
customer_id alanı NULL kabul ediyorsa bu değer, “ilişki bilinmiyor” veya “bu kayıt için ilişki uygulanmıyor” anlamına gelebilir. Ancak kolon NOT NULL tanımlıysa NULL kullanımı foreign key hatasından önce ayrı bir nullability hatası üretir.
customer_id gerçekten boş kalabilir mi, yoksa her sipariş mutlaka bir müşteriye mi ait olmalı sorusunu yanıtlayın. NULL değerini hatayı gizlemek için kullanmayın; yanlış ID sorununu görünmez hâle getirerek eksik ilişki verisi oluşturabilir. Çok kolonlu foreign key tanımlarında NULL davranışı ayrıca kullanılan motorun kurallarına göre doğrulanmalıdır.
5. ON DELETE ve ON UPDATE Davranışlarının Beklenmedik Sonucu
Parent müşteri silindiğinde veya customers.id değiştirildiğinde child siparişlere ne olacağı, constraint tanımındaki ON DELETE ve ON UPDATE seçeneklerine bağlıdır. RESTRICT ya da NO ACTION işlemi engelleyebilir; CASCADE ilişkili siparişleri silebilir veya ID’lerini güncelleyebilir; SET NULL ise child kolonunu boşaltabilir. Bu davranışlar tanıma ve kullanılan SQL motorunun uygulamasına göre değişebileceğinden, ilgili motorun foreign key belgeleri incelenmelidir.
Constraint'i Kaldırmadan Veri Bütünlüğünü Koruyan Çözüm Yolları
Çözüm, hatayı susturmak değil, hatanın temsil ettiği veri problemini düzeltmektir. Bu yaklaşımın ayrıntılı teknik konularla birlikte düzenli biçimde çalışılması için Berk Akademi’nin SQL ve yazılım geliştirme içerikleri de başvuru noktası olarak kullanılabilir.
| Belirti | Kontrol | Veri bütünlüğünü koruyan çözüm |
|---|---|---|
| Parent ID bulunamıyor | SELECT ile parent kaydı arayın |
İş kuralına uygunsa parent oluşturun; değilse işlemi durdurun |
| ID yanlış görünüyor | Uygulama parametresini ve kolon eşleştirmesini karşılaştırın | Doğru ID’yi gönderin veya veri aktarım hatasını düzeltin |
| İşlem sırası hatalı | Transaction adımlarını ve commit akışını inceleyin | Parent kaydı child kayıttan önce oluşturun |
| NULL ile işlem geçiştiriliyor | Kolonun NULL kabulünü ve iş anlamını doğrulayın |
NULL yalnızca gerçekten ilişki yoksa kullanılsın |
| Silme veya güncelleme engelleniyor | ON DELETE ve ON UPDATE tanımını inceleyin |
İş kuralına uygun RESTRICT, CASCADE veya SET NULL seçin |
Örneğin müşteri silindiğinde siparişlerin hukuken veya operasyonel olarak korunması gerekiyorsa ON DELETE CASCADE uygun olmayabilir. Buna karşılık yalnızca geçici sepet kayıtlarında cascade davranışı iş kuralıyla uyumlu olabilir. Constraint’i geçici olarak kapatmak, kaldırmak veya kontrolü atlamak ise teşhis yerine veri kalitesi sorununu erteleyebilir. Önce eksik parent kaydı, yanlış ID, işlem sırası ve ilişki tasarımı düzeltilmelidir.
Hata Mesajından Başlayan Foreign Key Kontrol Listesi
Foreign key hatasını çözmenin en güvenli yolu, hata mesajından geriye doğru ilerlemektir. Amaç constraint’i devre dışı bırakmak değil; hangi değerin, hangi tabloda ve hangi ilişki kuralını ihlal ettiğini kanıtlamaktır. Öğrenirken bu süreci uygulamalı SQL ve programlama dersleri içinde tekrar etmek, parent-child ilişkisini ezberden çok sistematik bir düşünme modeline dönüştürür.
- Kontrol sorusu: Hata INSERT işleminde mi, UPDATE işleminde mi oluştu ve hangi tablo ile kolon etkileniyor?
Kanıt: Hata mesajındaki tablo, constraint adı, SQL komutu ve uygulama logunu birlikte inceleyin. Örneğin hataorders.customer_idalanında oluşuyorsa sorun child tablodaki bu değerin ilişkisidir.
Düzeltme: Önce hatalı işlemi daraltın; INSERT ile UPDATE senaryolarını birbirine karıştırmadan ayrı ayrı test edin. - Kontrol sorusu: Veritabanına gerçekten hangi foreign key değeri gönderildi?
Kanıt: Sorgu parametrelerini veya uygulama logunu kontrol edin. Kullanıcıdan beklenencustomer_idyerineorder_id, boş değer, eski bir ID ya da yanlış ortamdan gelen bir ID gönderilmiş olabilir.
Düzeltme: Parametre sırasını ve kolon eşleştirmesini açıkça yazın:INSERT INTO orders (customer_id, total) VALUES (3, 250.00); - Kontrol sorusu: Parent tabloda bu anahtar gerçekten var mı?
Kanıt: Gönderilen değeri doğrudan sorgulayın:
Düzeltme: Sonuç dönmüyorsa önce doğruSELECT customer_id FROM customers WHERE customer_id = 3;customerskaydını oluşturun veya mevcut geçerli ID’yi kullanın. Birorderssatırı, karşılık gelen müşteri yokken anlamlı ve bağımsız bir kayıt olarak bırakılamaz. - Kontrol sorusu: Child foreign key ile parent primary veya unique key kolonu gerçekten eşleşiyor mu?
Kanıt: Her iki tablonunCREATE TABLEtanımını inceleyin.orders.customer_idalanı, yanlışlıklacustomers.emailya da başka bir kolonla ilişkilendirilmiş olabilir.
Düzeltme: İlişkiyi doğru anahtarlar üzerinden kurun; veri türü, kolon sırası ve çok kolonlu anahtar eşleşmelerini kontrol edin. - Kontrol sorusu: Parent kayıt child kayıttan önce mi oluşturuluyor ve işlemler aynı transaction kapsamında mı?
Kanıt: Uygulama akışında öncecustomers, sonraordersekleniyor mu kontrol edin.
Düzeltme: Önce parent kaydı ekleyin, oluşan anahtarı alın, ardından child kaydı ekleyin. Birden fazla işlem varsa transaction kapsamını açıkça yönetin. - Kontrol sorusu: NULL değeri ve silme-güncelleme kuralları iş kuralına uygun mu?
Kanıt: Foreign key kolonuNOT NULLmı, yoksa ilişkisiz kayıtlar için NULL kabul ediliyor mu? AyrıcaON DELETEveON UPDATEdavranışlarını inceleyin.
Düzeltme: İlişki zorunluysa geçerli parent ID kullanın. İlişki isteğe bağlıysa NULL tasarımını bilinçli uygulayın;CASCADEseçimini de child kayıtların silinmesinin gerçekten istenip istenmediğine göre yapın. - Kontrol sorusu: Aynı senaryo küçük ve güvenli bir test verisiyle tekrarlanabiliyor mu?
Kanıt: Test ortamında bir müşteri ve ona bağlı bir sipariş oluşturarak işlemi adım adım çalıştırın.
Düzeltme: Hata devam ediyorsa şema tanımını, parametreleri ve işlem sırasını yeniden karşılaştırın. SQLite gibi motorlarda foreign key denetiminin bağlantı ayarlarıyla ilişkili olabileceği için ilgili motorun resmi belgelerindeki SQLite foreign key dokümantasyonu ayrıca incelenmelidir.
Zihinsel şema şu şekilde kurulmalıdır: customers (parent) 1 ─── N orders (child). Bir müşteri birden çok siparişe bağlanabilir; ancak her siparişin iş kuralı gerektiriyorsa geçerli bir müşteri karşılığı bulunmalıdır.
Constraint’i Kaldırmadan Önce Sorulacak 7 Soru
- Hata tam olarak hangi tablo ve kolonda oluşuyor?
- Gönderilen foreign key değeri logda doğrulandı mı?
- Bu değer parent tabloda gerçekten mevcut mu?
- Kolon eşleştirmesi doğru primary veya unique key’e mi yapılıyor?
- Parent kayıt child kayıttan önce mi oluşturuluyor?
- NULL, ON DELETE ve ON UPDATE kuralları iş ihtiyacına uygun mu?
- Senaryo küçük bir test verisiyle güvenli biçimde yeniden üretildi mi?
Sık Sorulan Sorular
Foreign key hatasında ilk olarak hangi sorguyu çalıştırmalıyım?
Önce child kayda gönderilen ID’yi netleştirin ve ardından parent tabloda arayın: SELECT customer_id FROM customers WHERE customer_id = ?; Sonuç yoksa ilk şüphe eksik veya yanlış parent kaydıdır.
Parent kaydı varsa foreign key constraint failed hatası neden devam eder?
Gönderilen ID farklı olabilir, yanlış kolon eşleştirilmiş olabilir, veri türü veya çok kolonlu anahtar uyumsuzluğu bulunabilir. Ayrıca hata INSERT yerine UPDATE ya da silme işleminden kaynaklanıyor olabilir.
Foreign key kolonuna NULL vermek hatayı çözer mi?
Yalnızca kolon NULL kabul ediyorsa ve iş kuralında ilişkisiz child kayıtlar geçerliyse kullanılabilir. NULL, eksik parent kaydını gizlemek için rastgele uygulanacak bir çözüm değildir.
ON DELETE CASCADE kullanmak foreign key hatasını ortadan kaldırır mı?
Hayır. CASCADE, geçerli parent silindiğinde bağlı child kayıtlar için uygulanacak davranışı belirler. Yanlış ID ile yapılan INSERT veya UPDATE hatasını çözmez; ayrıca bağlı kayıtların topluca silinmesine neden olabilir.
SQLite ile diğer veri tabanı motorlarında foreign key kontrolü neden farklı görünebilir?
Motorların foreign key denetimini etkinleştirme, transaction kontrolü ve referans davranışları farklı olabilir. Bu nedenle aynı şema farklı bağlantı ayarlarında farklı sonuç verebilir; kullanılan motorun resmi belgeleriyle kontrol edilmelidir.
Foreign key hatasını kalıcı olarak çözmek için en doğru yaklaşım, ilişkiyi kaldırmak değil; veriyi, şemayı ve işlem sırasını kanıtlarla karşılaştırmaktır.