Menu

SQLite Self Join: Tabloyu Kendisiyle Birleştirme

SQLite'ta self join nasıl çalışır? Aynı tabloyu takma adlarla kendisine bağlama, çalışan/yönetici örneği ve hiyerarşik veri sorgulamaları.

Bu sayfada çalıştırılabilir editörler var — düzenle, çalıştır ve sonucu anında gör.

Self Join Aslında Alias'lı Bir Join'dir

Self join'in aslında özel bir tarafı yok. Sıradan bir JOIN işlemi, sadece iki tarafın da aynı tablo olduğu bir durum. İşin püf noktası şu: SQLite'ın bu iki kopyayı birbirinden ayırt edebilmesi gerekiyor, bu yüzden her birine bir alias veriyorsunuz.

Bu yönteme, bir tablodaki bir satırın aynı tablodaki başka bir satıra referans verdiği durumlarda başvurursunuz. En klasik örnek: her satırın başka bir çalışana işaret eden manager_id alanına sahip olduğu bir employees tablosu:

Ada'nın yöneticisi yok. Boris ve Cleo, Ada'ya bağlı çalışıyor. Diego ile Esme ise Boris'e raporluyor. Bu hiyerarşi tamamen tek bir tablonun içinde duruyor — işte tam da bu noktada self join devreye giriyor ve değerini gösteriyor.

Self Join Söz Dizimi: Temel Yapı

Her çalışanı kendi yöneticisinin adıyla eşleştirmek için employees tablosunu kendisiyle birleştiriyoruz. Bir kopya "çalışan" rolünü üstlenirken diğeri "yönetici" rolünü oynuyor:

İki ayrı tablo gibi düşün; sadece aynı yerde duruyorlar. e çalışan satırını, m ise yönetici satırını temsil ediyor. Birleştirme koşulu olan e.manager_id = m.id ikisini eşliyor: her çalışan için m tarafında id değeri o çalışanın manager_id'sine denk gelen satırı buluyor.

Dikkat ederseniz Ada sonuçta yok. Çünkü manager_id değeri NULL ve INNER JOIN eşleşmeyen satırları eliyor.

Eşleşmeyen Satırları Korumak: LEFT JOIN

Yöneticisi olmayanlar dahil herkesi sonuçta görmek istiyorsanız LEFT JOIN'e geçmeniz yeterli:

Artık Ada da listede görünüyor; yönetici sütununda NULL var. Self join mantığı aynı, sadece join tipi LEFT JOIN'in her zaman yaptığı şeyi yapıyor: sol taraftaki tüm satırları koruyor, eşleşme olmayan yerleri boş bırakıyor.

Bir kişi listesi gösteriyorsanız, genelde tam olarak bu davranışı istersiniz. "Yöneticisi yok" bilgisi de bir bilgidir; o satırı tamamen düşürmek olmaz.

Alias Kullanmak Zorunlu

Aynı sorguyu alias'sız yazmaya kalkarsanız SQLite ne demek istediğinizi anlayamaz:

SELECT name, manager_id FROM employees JOIN employees ON manager_id = id;
-- Hata: belirsiz sütun adı: name

Her sütun iki kez görünür — tablonun her bir kopyasından bir tane — ve SQLite hangisini seçeceğini bilemez. İşte tam burada alias'lar devreye girer ve her örneğe kendi adını vererek bu karmaşayı çözer. Alias seçerken tablo adını değil, satırın oynadığı rolü düşünün:

  • Çalışan/yönetici için e ve m.
  • Hiyerarşiler için parent ve child.
  • Rastgele çiftleri karşılaştırırken a ve b.

Bir self join'in temiz okunmasının asıl sebebi zaten alias'tır.

Aynı Tablodaki Satır Çiftlerini Bulma

Self join sadece hiyerarşiler için değildir. Aynı tablodaki satırları karşılaştırmak istediğiniz her durumda bu kalıp işinize yarar. Aşağıda bir ürün listesi var; amacımız aynı fiyata sahip tüm ürün çiftlerini bulmak:

Dikkat etmemiz gereken iki nokta var. Birincisi, asıl eşleştirme koşulu a.price = b.price. İkincisi ise a.id < b.id kısmı; bu da sorgunun her çifti iki kez döndürmesini (önce (Kupa, Defter), sonra (Defter, Kupa) olarak) ve her satırı kendisiyle eşleştirmesini engelliyor. O < numarasını aklınızın bir köşesinde tutun — çift listelemeniz gereken her durumda işinize yarayacak.

Hiyerarşide İki Seviye Yukarı Çıkmak

Tek bir self join, hiyerarşide tek bir adım atmanızı sağlar. Peki ya her çalışanın "yöneticisinin yöneticisini" bulmak isterseniz? O zaman üç kere join yapmanız gerekir:

Her yeni alias, ağaçta bir kademe daha yukarı çıkmak demek. İki ya da üç seviye için iş görür ama ondan sonrası çorba olur — sorguyu yazarken hiyerarşinin kaç seviye derin olduğunu bilmeniz ve her seviye için ayrı bir join eklemeniz gerekir. İşte tam da bu duvarı yıkmak için recursive CTE'ler icat edildi.

Self Join Kullanmamanız Gereken Durumlar

Self join, ilişkinin iki tarafından da sütunlara ihtiyaç duyduğunda doğru araçtır. Ama yalnızca filtreleme yapacaksanız — mesela yöneticisi Ada olan tüm çalışanları bulmak gibi — alt sorgu (subquery) genelde daha okunaklı durur:

No alias cambazlığı yok, niyet de gayet net. Pratik bir kural: çıktıda her iki satırdan da veri görmek istiyor musun? O zaman self join. Yalnızca karşılaştıracağın bir değer mi lazım? O zaman subquery.

Derinliği belirsiz hiyerarşilerde (organizasyon şemaları, dosya ağaçları, iç içe yorumlar) iki yaklaşım da ölçeklenmez. Orası artık recursive CTE'nin sahası.

Sırada: Subquery'ler

Self join ve subquery'ler benzer problemleri çözer; hangisinin nereye uyduğunu bilmek, ileride SQL'e gözlerini kısarak bakmaktan seni kurtarır. Bir sonraki sayfada subquery'leri enine boyuna ele alacağız — scalar, correlated ve IN biçimleriyle birlikte, hangisinin nerede parladığını da göreceksiniz.

Sıkça Sorulan Sorular

SQLite'ta self join nedir?

Self join, bir tablonun kendisiyle birleştirildiği klasik bir JOIN'dir. Aynı tabloya iki farklı takma ad verirsiniz; böylece SQLite onları iki ayrı satır kaynağıymış gibi ele alır. Sonra bir satırı diğerine bağlayan bir sütun üzerinden eşleştirme yaparsınız — en yaygın senaryo da çalışan/yönetici gibi ebeveyn-çocuk ilişkileridir.

Self join'de neden takma ad (alias) kullanmak zorundayım?

Takma ad olmadan, bir sütun adı yazdığınızda SQLite tablonun hangi kopyasından bahsettiğinizi ayırt edemez. Her örneğe kendi takma adını verirseniz (mesela çalışan için e, yönetici için m) e.manager_id = m.id gibi yazımlar net olur. Yani alias opsiyonel değil — onsuz sorgu zaten parse edilmez.

Self join mi, alt sorgu (subquery) mu kullanmalıyım?

Sonuç satırında her iki kayıttan da sütun göstermek istiyorsanız self join doğru tercihtir — örneğin çalışanın adı ile yöneticinin adını yan yana listelemek gibi. Sadece filtreleme yapacaksanız ya da tek bir değer arıyorsanız subquery yeter. Çok seviyeli, derin hiyerarşilerde ise ikisi de yetersiz kalır; orada doğru araç recursive CTE'dir.

Coddy programming languages illustration

Coddy ile kodlamayı öğren

BAŞLA