SQL JOIN sonuçları neden çoğalıyor sorusunun temel cevabı, JOIN işleminin koşulu sağlayan her kayıt çiftini ayrı bir sonuç satırı olarak döndürmesidir. Bir müşterinin birden fazla siparişi varsa müşteri sütunlarının her sipariş satırında tekrar görünmesi normaldir; ancak hatalı bir ON koşulu da beklenenden fazla eşleşme oluşturabilir.
Bu nedenle satır tekrarını düzeltmeden önce sonucun hangi varlık düzeyini temsil ettiğini, yani satır granülerliğini belirlemek gerekir. Aynı müşteri adının birkaç satırda görünmesi tek başına hata anlamına gelmez.
JOIN sonucu tek müşteri için neden birden fazla satır döndürür?
Bir JOIN sorgusunda sonuç satırı, soldaki tablodan bir kayıt ile sağdaki tablodan koşulu sağlayan bir kaydın oluşturduğu çifti temsil eder. Örneğin bir müşteri iki siparişe sahipse, müşteri ile birinci sipariş ve müşteri ile ikinci sipariş olmak üzere iki ayrı kayıt çifti oluşur. Sorgu bu çiftleri iki sonuç satırı olarak gösterir.
Satır granülerliği, sonuçtaki tek bir satırın neyi temsil ettiğini anlatır. Sadece müşteri bilgilerini döndüren bir sorgu müşteri düzeyinde olabilir. Müşteri ve sipariş bilgilerini birlikte döndüren sorgu ise çoğunlukla sipariş düzeyindedir. Bu durumda her satır bir siparişi temsil eder, müşteri bilgileri ise o siparişin sahibini belirtir.
- Bire bir ilişkide: Her kayıt en fazla bir kayıtla eşleşiyorsa sonuç satırları genellikle aynı sayıda kalır.
- Bire çok ilişkide: Bir sol kayıt, sağ tabloda kendisiyle eşleşen kayıt sayısı kadar sonuç satırı oluşturur.
- Çoka çok ilişkide: Aynı anahtara bağlı m sol kaydı ve n sağ kaydı varsa eşleşmeler m × n sayısına ulaşabilir.
JOIN satırları çoğaltmaz; eşleşen kayıt çiftlerini görünür kılar.
Dolayısıyla aynı müşteri bilgilerinin farklı siparişlerde yinelenmesi, sorgunun sipariş granülerliğinde çalıştığını gösterebilir. Sorun, beklenmeyen eşleşmelerin oluştuğu veya sorgunun hedeflediği granülerliğin yanlış belirlendiği durumda ortaya çıkar.
customers ve orders örneğinde satır artışı nasıl görünür?

Aşağıdaki örnekte bir müşterinin iki, diğer müşterinin bir siparişi bulunur:
CREATE TABLE customers (
customer_id INTEGER PRIMARY KEY,
customer_name VARCHAR(100) NOT NULL
);
CREATE TABLE orders (
order_id INTEGER PRIMARY KEY,
customer_id INTEGER NOT NULL,
total_amount DECIMAL(10, 2) NOT NULL,
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);
INSERT INTO customers (customer_id, customer_name) VALUES
(1, 'Ayşe'),
(2, 'Mert');
INSERT INTO orders (order_id, customer_id, total_amount) VALUES
(101, 1, 250.00),
(102, 1, 125.50),
(103, 2, 80.00);
SELECT
c.customer_id,
c.customer_name,
o.order_id,
o.total_amount
FROM customers AS c
INNER JOIN orders AS o
ON o.customer_id = c.customer_id
ORDER BY c.customer_id, o.order_id;
Bu sorgunun sonucu üç satırdır:
| customer_id | customer_name | order_id | total_amount |
|---|---|---|---|
| 1 | Ayşe | 101 | 250.00 |
| 1 | Ayşe | 102 | 125.50 |
| 2 | Mert | 103 | 80.00 |
Ayşe’nin müşteri bilgileri iki kez görünür çünkü iki farklı sipariş kaydıyla eşleşir. order_id değerleri farklı olduğu için bu satırlar özdeş kayıtlar değildir. Sorgu, müşterileri değil siparişleri gösterdiğinden üç satır üretmesi beklenen davranıştır.
Müşteri başına sipariş sayısını görmek için satırları GROUP BY ile müşteri düzeyinde özetleyebilirsin:
SELECT
c.customer_id,
c.customer_name,
COUNT(o.order_id) AS order_count
FROM customers AS c
INNER JOIN orders AS o
ON o.customer_id = c.customer_id
GROUP BY c.customer_id, c.customer_name
ORDER BY c.customer_id;
| customer_id | customer_name | order_count |
|---|---|---|
| 1 | Ayşe | 2 |
| 2 | Mert | 1 |
Satır artışının kaynağı üç aşamada nasıl teşhis edilir?

JOIN sonucundaki satır artışını teşhis ederken önce beklenen eşleşme sayısını hesapla, ardından ilişki anahtarlarını doğrula ve son olarak sorguyu adım adım çalıştır. Böylece artışın veri modelinden mi, kaynak veriden mi yoksa sorgu koşullarından mı geldiğini ayırabilirsin.
-
Her anahtarın kaç eşleşme ürettiğini incele. Önce JOIN işleminin sağındaki tabloda, her müşteri için kaç sipariş bulunduğunu ölç:
SELECT customer_id, COUNT(*) AS order_count FROM orders WHERE customer_id IN (101, 102) GROUP BY customer_id ORDER BY customer_id;Sonuçta
101numaralı müşteri için2,102numaralı müşteri için1sipariş görülüyorsa JOIN sonucunda toplam3satır beklenir. Müşteri tablosunda iki satır bulunmasına rağmen sonucun üç satır olması bu durumda hata değil, bire çok ilişkinin doğal sonucudur. -
Anahtarları, benzersizliği ve gerçek ilişki türünü kontrol et.
customers.customer_idbirincil anahtar,orders.customer_idise yabancı anahtar olmalıdır. Yabancı anahtarın sipariş tablosunda tekrarlanması normaldir. Buna karşılık benzersiz olması beklenen müşteri anahtarındaki tekrarlar araştırılmalıdır:SELECT customer_id, COUNT(*) AS record_count FROM customers GROUP BY customer_id HAVING COUNT(*) > 1;Beklenen sonuç sıfır satırdır. Sorgu kayıt döndürürse aynı müşteri anahtarı kaynak tabloda birden fazla kez bulunuyor olabilir veya benzersizlik varsayımı şema kısıtıyla korunmuyor olabilir.
-
WHERE ve JOIN adımlarını ayrı ayrı çalıştır. Önce temel satır sayısını, ardından her JOIN işleminden sonraki sayıyı karşılaştır:
SELECT COUNT(*) AS customer_rows FROM customers WHERE customer_id IN (101, 102); SELECT COUNT(*) AS rows_after_orders_join FROM customers AS c JOIN orders AS o ON o.customer_id = c.customer_id WHERE c.customer_id IN (101, 102);İlk sorgunun sonucu
2, ikinci sorgunun sonucu3olmalıdır. Daha uzun bir sorguda diğer JOIN işlemlerini ve WHERE koşullarını tek tek ekle. Satır sayısının beklenmedik biçimde değiştiği ilk adım, incelenmesi gereken tabloyu veya koşulu gösterir.
Beklenen bire çok ilişki ile hatalı eşleşme nasıl ayrılır?
Ayırıcı ölçüt, satırların ekranda aynı görünmesi değil, farklı bir olguyu temsil edip etmemesidir. Aynı müşteri bilgisi farklı sipariş kimlikleriyle görünüyorsa satırlar birbirinin kopyası değildir.
| Gözlem | Olası açıklama | Yapılacak kontrol |
|---|---|---|
Aynı customer_id, farklı order_id değerleriyle görünüyor. |
Beklenen bire çok ilişki | Müşteri başına sipariş sayısını ölç ve sipariş kimliklerinin farklı olduğunu doğrula. |
| Benzersiz olduğu düşünülen anahtar birden fazla kaynak kaydıyla eşleşiyor. | Yanlış ilişki varsayımı veya kaynak veride tekrar | Anahtarı GROUP BY ve HAVING COUNT(*) > 1 ile incele, şemadaki benzersizlik kısıtını kontrol et. |
| JOIN, ad, şehir veya durum gibi tekrarlanabilen sütunlarla kurulmuş. | Hatalı ON koşulu | Koşulu gerçek birincil anahtar ve yabancı anahtar ilişkisiyle karşılaştır. |
| İlişkiyi tanımlayan bileşik anahtarın yalnızca bir sütunu kullanılmış. | Eksik ON koşulu | Örneğin müşteri kimliğiyle birlikte şirket veya dönem kimliğinin de gerekli olup olmadığını denetle. |
| Her iki tabloda da eşleşen birden fazla kayıt bulunuyor. | İstenmeyen çoklu eşleşme | İki taraftaki eşleşme sayılarını ayrı ayrı ölç ve JOIN koşulunun ilişkiyi yeterince sınırlandırıp sınırlandırmadığını kontrol et. |
Görünür tekrar, seçilen sütunların aynı olmasıdır. Örneğin yalnızca müşteri adını seçmek, farklı order_id değerlerini gizleyebilir. Teşhis sırasında iki tablonun anahtarlarını da SELECT listesine eklemek, satırların gerçekten aynı mı yoksa yalnızca benzer mi olduğunu gösterir. Kaynak verideki gerçek mükerrerlik ise aynı varlığı tanımlayan anahtarın, veri modeline aykırı biçimde birden fazla kaynak satırında bulunmasıdır.
JOIN sonucu anlamı bozulmadan nasıl düzeltilir?
Önce satırları azaltmaya değil, istenen sonuç düzeyini belirlemeye odaklan. Sipariş ayrıntısı gerekiyorsa bir müşteriye ait birden fazla siparişi gösteren satırları korumak doğrudur. Müşteri başına tek özet gerekiyorsa COUNT veya SUM gibi toplulaştırmalarla GROUP BY kullanabilirsin.
Yalnızca siparişi bulunan müşterileri listelemek istiyorsan, sipariş tablosundaki sütunlara ihtiyaç duymadan EXISTS kullanmak daha uygun olur:
SELECT c.customer_id, c.customer_name
FROM customers AS c
WHERE EXISTS (
SELECT 1
FROM orders AS o
WHERE o.customer_id = c.customer_id
)
ORDER BY c.customer_id;
Örnek çıktı:
customer_id | customer_name
1 | Ayşe
2 | Mehmet
Ayşe'nin birden fazla siparişi olsa bile EXISTS, eşleşmenin varlığını kontrol eder ve müşteriyi bir kez döndürür. Yanlış eşleşme varsa çözüm, sonucu gizlemek değil, JOIN ON koşulunu düzeltmektir. İlişki tekil bir anahtara dayanıyorsa o anahtarı, bileşik anahtara dayanıyorsa anahtarın tüm sütunlarını koşula ekle. Aksi hâlde farklı kayıtlar aynı müşteri, kod veya dönem bilgisi üzerinden yanlış biçimde eşleşebilir.
DISTINCT yalnızca seçilen sütunların tamamı aynı olan satırları birleştirir. Farklı sipariş kimlikleri veya tutarlar seçiliyorsa satırlar farklı kabul edilir ve satır sayısı azalmaz. Bu sütunları seçmeden DISTINCT kullanmak ise çoğalmayı gizleyerek sipariş ayrıntısının kaybolmasına yol açabilir; bu nedenle hatalı JOIN koşulunun yerine geçmez.
Uygulama kontrol listesi:
- Hedef satır düzeyini belirle: sipariş ayrıntısı mı, müşteri özeti mi, yalnızca varlık kontrolü mü?
- Eşleşme anahtarını doğrula ve gerekiyorsa bileşik anahtarın tüm parçalarını kullan.
- Çözüm yöntemini seç: ayrıntıyı koru,
GROUP BYile özetle veyaEXISTSile varlığı denetle. - Satır sayısını ve örnek kayıtları yeniden karşılaştır.
Sık Sorulan Sorular
LEFT JOIN neden tek müşteri için birden fazla satır döndürür?
Sol tablodaki bir müşteri, sağ tablodaki birden fazla siparişle eşleşiyorsa LEFT JOIN her eşleşme için ayrı satır üretir. Hiç eşleşme yoksa müşteri genellikle bir kez, sağ tablo sütunları boş değerlerle döner.
DISTINCT kullandığım hâlde satır sayısı neden azalmıyor?
Seçilen sütunlardan en az biri satırlar arasında farklıdır. Sipariş kimliği, tarih veya tutar gibi değerler farklı kaldığı sürece DISTINCT bu satırları aynı kabul etmez.
JOIN koşulunda bileşik anahtarın bir sütununu unutmak sonucu nasıl etkiler?
Koşul eksik kaldığında farklı anahtar parçalarına sahip kayıtlar da eşleşebilir. Bu durum yanlış kombinasyonlar ve beklenenden fazla satır oluşturur.
GROUP BY ile EXISTS arasında nasıl seçim yapılır?
Her müşteri için toplam, adet veya başka bir özet hesaplayacaksan GROUP BY kullan. Yalnızca müşterinin en az bir siparişi olup olmadığını kontrol edeceksen EXISTS daha doğrudan bir seçimdir.
Doğru çözüm, çoğalan satırları otomatik olarak silmek değil, sorgunun üretmesi gereken satır düzeyini korumaktır.