Veritabanı Sorgularında SQL Join İşlemleri: Verileri Birleştirme Rehberi
SQL Join işlemi temel olarak adından da anlaşılabileceği gibi birden fazla tablodaki verileri birleştirmek için kullanılan yapılardır.
Genellikle birincil anahtarlar (primary keys
) veya foreign key
’ler aracılığıyla istediğimiz verilerin sorgulamasında tabloları birleştirmek için kullanılmaktadır. Bazı durumlarda birincil anahtar veya yabancı anahtar olmadan da JOIN
işlemi gerçekleştirebiliririz. Bu durumda, JOIN
işleminde sütunlar arasındaki benzerlikleri kullanarak tabloları birleştirebiliriz. Ancak, bu yöntem genellikle tavsiye edilmez çünkü doğruluk ve performans sorunlarına neden olabilir. Yani, JOIN
işlemlerinde birincil anahtar veya yabancı anahtar kullanmak genellikle daha iyi bir yaklaşımdır. Bu, tablolar arasındaki ilişkiyi belirlemek ve daha doğru sonuçlar elde etmek için iyi bir veritabanı tasarımı gerektirir.
Basitçe JOIN işlemi iki temel keywordle birlikte gelir. JOIN
ve ON
keywordlerini kullanırız. JOIN işleminde SELECT
ile belirtilen tabloyla birleştirmek istediğimiz tablonun adını JOIN
anahtar kelimesinden sonra ifade edebiliriz. ON
anahtar kelimesi ile birlikte iki tablodaki hangi sütunları baz alarak birleştirebileceğimizi söyleyebiliriz.
SELECT *
FROM table1
JOIN table2 ON table1.column1 = table2.column2;
Bu örnekte, table2
tablosu ile table1
tablolarını JOIN ederken, column1
sütunuyla column2
sütununu eşleştirerek bu birleştirme işlemini gerçekleştirilmesini söylüyoruz.
Basitçe join ifadesinin ne amaçla kullanıldığını, ne işe yaradığını ve temel bir join işleminin nasıl yapılabileceğini özetlemiş olduk. Şimdi biraz daha derinliklerine giderek farklı tipteki joinlerin hangi durumda hangi join işlemini kullanmamız gerektiğinide anlatalım. Bunun için ilk önce tablolarımızı yaratalım ve içlerine biraz veri ekleyelim.
CUSTOMER
tablosunun oluşturulması ve veri ekleme:
CREATE TABLE customers (
customer_id INT PRIMARY KEY,
customer_name VARCHAR(100),
city VARCHAR(50),
country VARCHAR(50)
);
INSERT INTO customers (customer_id, customer_name, city, country)
VALUES (1001, 'Ahmet Yılmaz', 'İstanbul', 'Türkiye');
INSERT INTO customers (customer_id, customer_name, city, country)
VALUES (1002, 'Ayşe Demir', 'Ankara', 'Türkiye');
INSERT INTO customers (customer_id, customer_name, city, country)
VALUES (1003, 'Mehmet Kaya', 'İzmir', 'Türkiye');
INSERT INTO customers (customer_id, customer_name, city, country)
VALUES (1004, 'Fatma Öztürk', 'Bursa', 'Türkiye');
INSERT INTO customers (customer_id, customer_name, city, country)
VALUES (1005, 'Ali Can', 'Adana', 'Türkiye');
INSERT INTO customers (customer_id, customer_name, city, country)
VALUES (1006, 'Zeynep Gül', 'Antalya', 'Türkiye');
ORDER
tablosunun oluşturulması ve veri ekleme:
CREATE TABLE orders (
order_id INT PRIMARY KEY,
order_date DATE,
customer_id INT,
total_amount DECIMAL(10, 2)
FOREIGN KEY (CustomerID) REFERENCES Customers(CustomerID)
);
INSERT INTO orders (order_id, order_date, customer_id, total_amount)
VALUES (1, '2023-04-01', 1001, 150.00);
INSERT INTO orders (order_id, order_date, customer_id, total_amount)
VALUES (2, '2023-04-05', 1002, 200.00);
INSERT INTO orders (order_id, order_date, customer_id, total_amount)
VALUES (3, '2023-04-10', 1003, 75.50);
Yukarıdaki sorgular, ORDER
ve CUSTOMER
tablolarını oluşturur ve örnek verileri ekler.
JOIN TIPLERI VE KULLANIMI
JOIN işlemi, farklı JOIN tipleri ile çeşitli senaryolara uygun şekilde uygulanabilir.
- INNER JOIN: Bu JOIN türü, birincil tablo ve eşleşen kayıtları olan diğer tablo arasında birleştirme yapar. INNER JOIN, her iki tablodan yalnızca eşleşen kayıtları getirir.
SELECT *
FROM orders
INNER JOIN customers
ON orders.customer_id = customers.customer_id;
Bu örnek, orders
ve customers
tablolarını INNER JOIN
ile birleştirir ve her iki tablodan yalnızca eşleşen kayıtları getirir. Burada, ON
ifadesiyle, orders
tablosundaki customer_id
sütunu ile customers
tablosundaki customer_id
sütunu eşleştirilir.
- LEFT JOIN: Bu JOIN türü, birincil tablodaki tüm kayıtları ve eşleşen kayıtları olan diğer tablodaki kayıtları birleştirir.
LEFT JOIN
, her iki tablodan yalnızca eşleşen kayıtları getirirken, birincil tablodaki tüm kayıtları da getirir.
SELECT *
FROM customers
LEFT JOIN orders
ON customers.customer_id = orders.customer_id;
Bu örnek, customers
tablosundaki tüm kayıtları ve orders
tablosundaki eşleşen kayıtları birleştirir. Ancak, orders
tablosunda eşleşen kayıt yoksa bile, customers tablosundaki tüm kayıtları getirir. Eşleşmeyen kayıtlar ise NULL
değerleri ile doldurularak gösterilir.
- RIGHT JOIN: Bu
JOIN
türü, diğer tablodaki tüm kayıtları ve eşleşen kayıtları olan birincil tablodaki kayıtları birleştirir.RIGHT JOIN
, her iki tablodan yalnızca eşleşen kayıtları getirirken, ikincil tablodaki tüm kayıtları da getirir.
SELECT *
FROM orders
RIGHT JOIN customers
ON orders.customer_id = customers.customer_id;
Bu örnekte ise yine customers
tablosunda ki değerleri görebilmek için bu sefer orders tablosundaki tüm kayıtları ve customers tablosundaki eşleşen kayıtları birleştirir. Ancak, customers tablosunda eşleşen kayıt yoksa bile, orders tablosundaki tüm kayıtları getirir. Eşleşmeyen kayıtlar ise NULL
değeri ile gösterilir.
- FULL OUTER JOIN: iki tablodaki tüm kayıtları getirir ve eşleşmeyen kayıtlar NULL değeri ile doldurulur.
FULL OUTER JOIN
,LEFT JOIN
veRIGHT JOIN
işlemlerinin birleşimi gibi çalışır ve genellikle bir tabloda bulunan tüm kayıtların diğer tablodaki ilgili kayıtlarının alınması gereken durumlarda kullanılır.
SELECT *
FROM customers
FULL OUTER JOIN orders ON customers.customer_id = orders.customer_id;
WHERE Yapıları ile Join Işlemi Yapılabilir mi?
JOIN işlemi ile WHERE komutu arasında doğrudan bir denklik yoktur. JOIN işlemi, ilişkili kayıtları birleştirmek için kullanılırken, WHERE
komutu ise filtreleme işlemleri için kullanılır. Yine de tabloları birleştirmek için kullanılabilen bir yöntemdir. Bu yöntem, eski bir JOIN formatıdır.
SELECT *
FROM orders, customers
WHERE orders.customer_id = customers.customer_id;
Bu sorgu da customer_id
sütununu kullanarak orders
ve customers
tablolarını birleştirir.
Frameworkler’de durumlar nasil?
Frameworkler işlerimizi kolaylaştırıyor ve bizim için hazır Repository’ler aracılığıyla sorguları otomatik oluşturabiliyor. Peki join işlemlerinde nasıl bir davranış sergiliyorlar biraz bu soruyu irdeleyelim. Örneğin Order
sınıfımızda böyle bir join işlemi uygulayalım.
@JoinTable( name = "order_customer",
joinColumns = @JoinColumn(name = "customer_id"))
private Customer customer;
Basitçe Repositoryimizi oluşturalım. Join işleminin arkada nasıl bir sorgu oluşturduğunu inceleyebiliriz.
@Repository
public interface OrderRepo extends JpaRepository<Order, Long> {
List<Order> findByCustomerId(Long customerId);
}
Aslında sadece ingilizce sözcükler yazarak Frameworklerin ne kadar kolay bir şekilde sorgu ürettiğini görebiliriz. Arka planda ise raw query
olarak bize otomatik oluşturulmuş sorgular ürettiğini tahmin edebiliriz.
select o1_0.order_id,o1_0.total_amount,o1_1.customer_customer_id from orders o1_0 left join order_customer o1_1 on o1_0.order_id=o1_1.customer_id where o1_1.customer_customer_id=?
Oluşturulan sorgunun kolay okunabilir olmadığını söyleyebiliriz. Oluşturulan sorgu LEFT JOIN işlemi kullanılarak yapıldığını görebilirsiniz. Biz tablolarını join ettiğimiz için aslında çok mantıklı ve tutarlı bir çözüm üretmiş gibi duruyor. Farklı ve daha sık kullanılan bir birleştirme yöntemi kullandığımızda durum biraz daha farklılaşıyor.
@JoinColumn(name = "customer_id")
private Customer customer;
Böyle bir join işleminde aslında yaptığımız tabloları join etmek olmadığı için framework tabloları birleştirme ihtiyacını gütmüyor. Aynı Repository’i kullansak bile yaptığımız işlem tamamen farklı bir raw query
’e bürünüyor.
select o1_0.order_id,o1_0.customer_id,o1_0.total_amount from orders o1_0 where o1_0.customer_id=?
Görüldüğü üzere tabloları birleştirmesini söylemediğimiz için daha önce de belirttiğimiz üzere WHERE
koşulu ile bir filtreleme görevi görüyor. Daha farklı sorgularda daha farklı sonuçlar almak mümkün. Özellikle kompleks veya çok fazla veri çekmemiz gereken query’lerde oluşuturulan raw query
leri debug modda incelemeliyiz. Performansı etkileyecek parçalar var ise otomatik oluşuturulmuş query’ler yerine kendimizin raw query
yazması daha fazla performans sağlayabilir. Dolayısıyla veritabanı işlemlerinde her zaman bi gözümüz oluşturulan query’lerde olursa uygulamamızın performansına yönelik hamleler yapabilmemiz kolaylaşacaktır.
SONUÇ
Join işlemleri özellikle tabloları birleştirmek için kullanılan temel SQL komutlarından biridir, birden fazla farklı tipi bulunur ve bunlar ihtiyaca göre doğru bir şekilde kullanılmalıdır.
Genel olarak, JOIN işlemlerini kullanırken dikkat etmeniz gereken noktalar; veri yoğunluğu, yetersiz/yanlış indeksleme, yanlış joinler sonucu fazla veri dönme sorunu ve yanlış PK ve FK kullanımı, veritabanı tasarımı gibi faktörleri göz önünde bulundurmanızdır. Bu durumlar, JOIN işlemlerinin performansını etkileyebilir ve gereksiz karmaşıklığa yol açabilir. Alternatif yaklaşımların kullanılması veya veritabanı tasarımının yeniden değerlendirilmesi gerekebilir.
Belirtilen tüm SQL sorgularını online olarak deneyebilirsiniz: https://sqliteonline.com/