Berk Akademi
Ana Sayfa
ÖZEL KODLAMA DERSLERİ
Yazılım Özel Ders
Tüm birebir programlara genel bakış
Python Yazılım Kursu
Sıfırdan ileri seviyeye birebir Python
Java Yazılım Kursu
OOP odaklı birebir Java eğitimi
AP Computer Science Principles
AP CSP sınav hazırlığı
GRUP DERSLERİ
Python & Django Masterclass
SINIRLI KONTENJAN
Java & Spring Boot Masterclass
SINIRLI KONTENJAN
C# .NET Masterclass
SINIRLI KONTENJAN
VİDEO DERSLER
Sıfırdan Temel Python Kursu
Kendi Hızında Öğren
ÜCRETSİZ
Seviye Testi
Ücretsiz — Python, Java, algoritma seviye testleri
Kariyerini Keşfet
Sertifika Doğrula
Belge numarası ve soyad ile doğrulama

SQL JOIN Sonrası Fazla Satır Sorunu Nasıl Çözülür?

sql-join-sonrasi-fazla-satir-sorunu-nasil-cozulur
Bu yazıda neler var?
  1. JOIN Sonucunda Satırlar Neden Çoğalır?
  2. Yanlış JOIN Koşulu ve ON-WHERE Farkı
  3. Dört Adımlı Satır Çoğalması Teşhisi
  4. 1. Adım: Tabloları Tek Başına Ölçmek
  5. 2. ve 3. Adım: Anahtar ile Kardinaliteyi Doğrulamak
  6. 4. Adım: DISTINCT, GROUP BY veya Model Kararı
  7. Sık Sorulan Sorular

SQL JOIN fazla satır sorunu çoğunlukla sorgunun veriyi beklenenden fazla eşleştirmesinden kaynaklanır. Önce ilişkinin 1-N mi, N-N mi olduğunu belirleyin; ardından JOIN koşulundaki anahtarları ve filtrelerin ON ya da WHERE içinde bulunması gerektiğini kontrol edin. Müşteri başına üç sipariş varsa sonuçta aynı müşterinin üç kez görünmesi hata değil, ilişkinin doğal sonucudur.

Sorunu çözmek için satır sayısını doğrudan azaltmaya çalışmak yerine eşleşmenin neden çoğaldığını bulun. DISTINCT veya GROUP BY kullanmadan önce beklenen satır sayısını, anahtarların benzersizliğini ve JOIN’in gerçekten hangi kayıtları eşleştirdiğini doğrulayın.

JOIN Sonucunda Satırlar Neden Çoğalır?

Bir müşterinin birden fazla siparişi varsa müşteri ve sipariş tabloları arasındaki ilişki 1-N şeklindedir. Müşteri tablosunda Ali için tek satır, sipariş tablosunda Ali’ye ait üç satır bulunuyorsa JOIN sonucu Ali’nin bilgileri üç satırda tekrarlanır. Bu, müşteri kaydının fiziksel olarak çoğaldığı anlamına gelmez; sorgu her eşleşen sipariş için bir sonuç satırı üretir.

Örneğin bir müşterinin iki siparişi olduğunu düşünelim:

SELECT c.name, o.id AS order_id
FROM customers AS c
JOIN orders AS o
  ON o.customer_id = c.id
WHERE c.id = 1;

Beklenen çıktı müşteri başına bir satır değil, sipariş başına bir satırdır:

name       | order_id
-----------+---------
Ayşe       | 101
Ayşe       | 102

Burada “Ayşe iki kez geldi” gözlemi doğrudur; ancak sorgunun amacı siparişleri listelemekse sonuç beklenendir. Sorun, uygulama yalnızca müşteri başına tek satır beklerken sipariş detaylarının da aynı sorguya eklenmesiyle ortaya çıkar.

İki tarafta da birden fazla eşleşen kayıt varsa ilişki N-N davranışı gösterir. Örneğin bir siparişin birden fazla ürünü, bir ürünün de birçok siparişi olabilir. Bu durumda sonuç satırları müşteri-sipariş değil, müşteri-sipariş-ürün birleşimlerini temsil eder. Aynı sorguda iki ayrı 1-N ilişkiyi doğrudan birleştirmek de satır sayısını çarpabilir.

Yanlış JOIN Koşulu ve ON-WHERE Farkı

Yanlış JOIN Koşulu ve ON-WHERE Farkı

Fazla satırların en yaygın nedenlerinden biri, tabloları bağlayan anahtarın ON koşulunda eksik veya yanlış kullanılmasıdır. Örneğin yalnızca sipariş durumunu karşılaştırmak, fakat müşteri anahtarını yazmamak, her müşterinin aynı durumdaki tüm siparişlerle eşleşmesine neden olabilir.

SELECT c.name, o.id AS order_id
FROM customers AS c
JOIN orders AS o
  ON o.status = 'paid';

Örneğin iki müşteri ve üç adet paid sipariş varsa sorgu, müşteri-sipariş ilişkisini değil, iki müşteri ile üç siparişin çapraz eşleşmesini üretir: toplam altı satır. Doğru koşul, ilişki anahtarını da içermelidir:

SELECT c.name, o.id AS order_id
FROM customers AS c
JOIN orders AS o
  ON o.customer_id = c.id
 AND o.status = 'paid';

LEFT JOIN kullanırken filtreyi nereye yazdığınız da sonucu değiştirir. Filtre ON içinde olursa müşteriler korunur, yalnızca eşleşen siparişler bağlanır:

SELECT c.name, o.id AS order_id
FROM customers AS c
LEFT JOIN orders AS o
  ON o.customer_id = c.id
 AND o.status = 'paid';

Bu sorguda hiç ödenmiş siparişi olmayan müşteri de sonuçta yer alır; order_id değeri NULL olur. Aynı filtreyi WHERE içine taşırsanız:

SELECT c.name, o.id AS order_id
FROM customers AS c
LEFT JOIN orders AS o
  ON o.customer_id = c.id
WHERE o.status = 'paid';

WHERE koşulu, JOIN sonrasında NULL oluşan satırları eler. Böylece sorgu yalnızca ödenmiş siparişi bulunan müşterileri döndürür ve pratikte LEFT JOIN davranışı daralır. Fazla satır araştırırken önce ON koşulunda tüm ilişki anahtarlarının bulunup bulunmadığını, ardından filtrelerin eşleşme aşamasında mı yoksa sonuç aşamasında mı uygulanması gerektiğini kontrol edin.

Dört Adımlı Satır Çoğalması Teşhisi

SQL JOIN sonrası fazla satır görüyorsanız doğrudan DISTINCT eklemek yerine çoğalmanın hangi tabloda ve hangi anahtar ilişkisinde oluştuğunu ölçün. Aşağıdaki dört adım, sorunu görünür hâle getirir. Bu yaklaşım, algoritmik düşünmede olduğu gibi önce girdileri, sonra ilişkileri ve en sonunda çözüm kararını kontrol eder. Temel sorgu mantığını geliştirmek için algoritma bilgi testi üzerinden kendi seviyenizi de ölçebilirsiniz.

  1. Tabloları tek başına sayın. Önce customers ve orders tablolarının toplam satırlarını, ayrıca müşteri başına sipariş sayılarını kontrol edin.
    SELECT COUNT(*) AS customer_count
    FROM customers;
    
    SELECT customer_id, COUNT(*) AS order_count
    FROM orders
    GROUP BY customer_id
    ORDER BY customer_id;

    Beklenen çıktı: customer_count = 3; müşteri bazında (1, 2), (2, 1), (3, 3). Sonuç, bazı müşterilerin birden fazla siparişi olduğunu gösterir.

  2. Anahtar benzersizliğini doğrulayın. JOIN koşulunda kullanılan alanın gerçekten tekil olup olmadığını kontrol edin.
    SELECT customer_id, COUNT(*) AS tekrar
    FROM customers
    GROUP BY customer_id
    HAVING COUNT(*) > 1;

    Beklenen çıktı: boş sonuç. Eğer satır dönerse customers.customer_id tekil değildir ve müşteri tablosu da satır çoğalmasına katkı veriyor olabilir.

  3. Kardinaliteyi ölçün. JOIN sonrasında her müşterinin kaç satıra dönüştüğünü görün.
    SELECT c.customer_id, COUNT(o.order_id) AS joined_rows
    FROM customers AS c
    LEFT JOIN orders AS o
      ON o.customer_id = c.customer_id
    GROUP BY c.customer_id
    ORDER BY c.customer_id;

    Beklenen çıktı: (1, 2), (2, 1), (3, 3). Müşteri başına tek satır beklenirken bu değerler birden fazlaysa çoğalma, bire-çok ilişkisinin doğal sonucudur.

  4. Çözüm kararını verin. İhtiyaç müşteri başına özet bilgi ise gruplama yapın; tüm sipariş ayrıntıları gerekiyorsa satırların çoğalmasını hata kabul etmeyin.
    SELECT c.customer_id, COUNT(o.order_id) AS order_count
    FROM customers AS c
    LEFT JOIN orders AS o
      ON o.customer_id = c.customer_id
    GROUP BY c.customer_id;

    Beklenen çıktı: müşteri başına üç satır ve sipariş adetleri 2, 1, 3. Böylece DISTINCT ile veriyi gizlemek yerine doğru çıktı biçimi seçilir.

1. Adım: Tabloları Tek Başına Ölçmek

1. Adım: Tabloları Tek Başına Ölçmek

İlk ölçüm JOIN içermemelidir. Müşteri ve sipariş tablolarını ayrı ayrı sayarak beklenen sonucu tahmin edin:

SELECT
  (SELECT COUNT(*) FROM customers) AS customers,
  (SELECT COUNT(*) FROM orders) AS orders,
  (SELECT COUNT(DISTINCT customer_id) FROM orders) AS ordering_customers;

Örneğin çıktı customers = 3, orders = 6 ve ordering_customers = 3 ise JOIN sonucunun altı satır civarında olması, müşteri başına sipariş ayrıntısı isteniyorsa normaldir. Müşteri başına tek satır hedefleniyorsa ise önce siparişleri GROUP BY customer_id ile özetlemek gerekir.

Şimdi dağılımı doğrudan inceleyin:

SELECT customer_id, COUNT(*) AS order_count
FROM orders
GROUP BY customer_id
ORDER BY order_count DESC;

Çıktıda bir müşteri için order_count = 3 görülüyorsa, bu müşterinin JOIN sonrasında üç kez görünmesi tek başına yanlış JOIN kanıtı değildir. Hata şüphesi ancak beklenen rapor müşteri başına tek satır olduğu hâlde ayrıntılı sipariş satırları seçildiğinde güçlenir.

2. ve 3. Adım: Anahtar ile Kardinaliteyi Doğrulamak

JOIN sonrasında oluşan fazla satırları çözmenin en güvenilir yolu, önce JOIN anahtarının gerçekten benzersiz olup olmadığını kontrol etmektir. Örneğin customers.customer_id tekil olabilirken, orders.customer_id aynı müşteri için birçok kez bulunabilir. Bu durumda ilişki 1-N’dir: bir müşteri, birden fazla siparişe sahip olabilir.

2. Adım: Anahtardaki tekrarları GROUP BY ve HAVING ile bulmak

Aşağıdaki sorgu, orders tablosunda aynı müşteriye ait birden fazla kayıt olup olmadığını gösterir:

SELECT
    customer_id,
    COUNT(*) AS order_count
FROM orders
GROUP BY customer_id
HAVING COUNT(*) > 1
ORDER BY customer_id;

Beklenen çıktı şöyle olabilir:

customer_id order_count
101 3
205 2

Bu çıktı, JOIN koşulunda customers.customer_id = orders.customer_id kullanıldığında aynı müşterinin birden fazla kez görünmesinin normal olabileceğini gösterir. Buradaki sorun her zaman yanlış JOIN değildir; sorgunun beklediği sonuç seviyesi ile tablonun gerçek kardinalitesi birbirinden farklı olabilir.

3. Adım: İlişkiyi gerçek kayıtlarla sınıflandırmak

İki tablo arasındaki ilişkiyi yalnızca kolon adına bakarak değil, gerçek kayıtları ölçerek sınıflandırın:

  • 1-1: Birinci tablodaki her kayıt, ikinci tabloda en fazla bir kayıtla eşleşir.
  • 1-N: Birinci tablodaki bir kayıt, ikinci tabloda birden fazla kayıtla eşleşebilir.
  • N-N: Her iki tarafta da tekrarlar vardır ve ilişki genellikle ara tablo üzerinden kurulur.

Müşteri ve sipariş ilişkisini ölçmek için:

SELECT
    c.customer_id,
    c.name,
    COUNT(o.order_id) AS matched_orders
FROM customers AS c
LEFT JOIN orders AS o
    ON o.customer_id = c.customer_id
GROUP BY c.customer_id, c.name
ORDER BY matched_orders DESC;

Beklenen çıktı: customer_id = 101 için matched_orders = 3, başka bir müşteri için matched_orders = 0 görülebilir. Sıfır değer, LEFT JOIN sayesinde siparişi olmayan müşterinin de korunduğunu gösterir. Bir müşteri için üç eşleşme oluşması ise müşteri bilgilerinin üç kez kopyalanması değil, JOIN sonucunun sipariş seviyesine inmesidir.

N-N ilişkilerde çoğunlukla order_items gibi bir ara tablo bulunur. Bir siparişin birçok ürünü, bir ürünün de birçok siparişi olabilir. Bu yapıyı tek JOIN ile müşteri, sipariş ve ürün düzeylerini karıştırarak sorgulamak; satırların beklenenden hızlı çoğalmasına yol açabilir.

4. Adım: DISTINCT, GROUP BY veya Model Kararı

Satır çoğalmasının kaynağı belirlendikten sonra çözüm, sorgunun hangi sonucu üretmesi gerektiğine göre seçilmelidir. DISTINCT yalnızca aynı seçili kolonlara sahip tekrarları kaldırır; farklı sipariş veya ürün bilgileri sonuçta yer alıyorsa satırları birleştirmez. GROUP BY ise toplam, adet veya son işlem tarihi gibi özetler üretmek için kullanılır.

Durum Doğru yaklaşım Kaçınılması gereken yaklaşım
Yalnızca benzersiz müşteri listesi gerekiyor DISTINCT customer_id Detay kolonlarını ekleyip DISTINCT’in her şeyi çözmesini beklemek
Müşteri başına sipariş sayısı gerekiyor GROUP BY customer_id ve COUNT Detay satırlarını filtrelemeden listelemek
Her siparişin ürünleri gerekiyor 1-N ilişkiyi kabul ederek detay sonuç döndürmek Sonucu zorla tek satıra indirmek
İki tarafta da tekrar var Ara tablo ve doğru veri modeliyle JOIN yapmak Rastgele DISTINCT eklemek

Örneğin müşteri başına tek satır isteniyorsa:

SELECT
    c.customer_id,
    c.name,
    COUNT(o.order_id) AS order_count
FROM customers AS c
LEFT JOIN orders AS o
    ON o.customer_id = c.customer_id
GROUP BY c.customer_id, c.name;

Bu sorgunun beklenen çıktısı, her müşteri için tek satır ve o müşteriye ait sipariş adedidir. JOIN mantığını ve sorgu seviyelerini uygulamalı biçimde pekiştirmek isteyenler, birebir Python dersleri kapsamında benzer veri işleme problemlerini adım adım çalışabilir.

Sonuç hâlâ beklenenden farklıysa sorun yalnızca SQL yazımında olmayabilir. Aynı anahtarın birden fazla kaydı temsil etmesi, veri modelinin doğal sonucu olabilir. Bu durumda sorguyu gizlemek yerine ilişkiyi açıkça modellemek ve hangi seviyede çıktı istendiğini netleştirmek gerekir.

Sık Sorulan Sorular

SQL JOIN neden aynı müşteriyi birden fazla kez gösterir?

Çünkü JOIN yapılan tabloda aynı müşteriye ait birden fazla kayıt olabilir. Müşteri tablosundaki tek kayıt, sipariş tablosundaki üç kayıtla eşleşiyorsa sonuçta müşteri üç satırda görünür. Bu durum çoğu zaman 1-N ilişkisinin doğal sonucudur.

DISTINCT kullanmak JOIN kaynaklı satır çoğalmasını her zaman çözer mi?

Hayır. DISTINCT yalnızca seçilen kolonların tamamı aynı olan satırları kaldırır. Sipariş numarası, ürün adı veya tarih gibi farklı kolonlar seçiliyorsa satırlar birbirinden farklı kabul edilir. Müşteri başına toplam veya adet gerekiyorsa GROUP BY ve toplama fonksiyonları daha doğru seçimdir.

LEFT JOIN koşulu ON içine mi, WHERE içine mi yazılmalıdır?

İkinci tablodaki eşleşme koşulları genellikle ON içinde tutulmalıdır. WHERE koşulu, eşleşmeyen satırları filtrelerse LEFT JOIN’in dış birleştirme davranışını fiilen daraltabilir. Bu nedenle koşulun eşleşmeyi mi, nihai sonucu mu filtrelediği ayrıştırılmalıdır.

Bir JOIN anahtarının benzersiz olup olmadığı nasıl kontrol edilir?

Kolonu GROUP BY ile gruplayıp HAVING COUNT(*) > 1 kullanarak tekrarları bulabilirsiniz. Sonuç dönmüyorsa ilgili değerler tekrar etmiyor olabilir; ancak kesin değerlendirme için tablo kısıtları ve veri modeli de incelenmelidir.

Doğru çözüm, fazla satırı körlemesine silmek değil; JOIN’in hangi ilişkiyi ve hangi sonuç seviyesini temsil ettiğini doğrulamaktır.

Bu içerik aradığın cevabı verdi mi?
Yanıtın, hangi yazıları geliştirmemiz gerektiğini anlamamıza yardımcı olur.
Bu içeriğin üretilmesinde yapay zeka araçlarından destek alınmıştır.

Bu konudan sonra ne okuyabilirsin?

Tüm yazılar

İlgili Eğitimler

Berk Keskin — Yazılım Geliştirici ve Eğitmen
Yazar

Berk Keskin Kimdir?

Yazılıma 12 yaşında başladı; bugün öğrencinin seviyesine ve hedefine göre şekillenen sürdürülebilir öğrenme sistemleri tasarlıyor. 500'den fazla kişiye ezber değil, düşünerek kod yazmayı öğretti — Berk Akademi'de izlemeye değil üretmeye dayalı öğrenme kültürünü o kuruyor.

WhatsApp Hemen Ara