İleri seviye SQL kullanımında, standart JOIN ile ilişkilendirmelerin artık işe yaramamaya başladığı ve iç içe SELECT sorguları yazmaya başladığınızda, aynı alt-sorgunun hem SELECT içinde, hem WHERE içinde belki başka bloklarda da kullanmanız gerekebilir.
İşte o zaman bu alt-sorgular RDBMS’in canına okuyacaktır. Eğer bir SQL GURU’su iseniz ne dediğimi çoktan anlamışsınızdır 🙂
Bu problemin çözümü PostgreSQL ‘de LATERAL, MSSQL’de CROSS APPLY, Oracle’da da LATERAL ve kullanımı PostgreSQL ile aynı. MySQL’de bu işlevi yerine getirecek bir terim henüz mevcut değil.
Şimdi bir ilişkisel veri tabanı modeli çıkartalım ve örneklerimizi onun üzerinden anlatalım:
PostgreSQL için SQL kodları:
CREATE TABLE tbl_category ( category_id SERIAL NOT NULL, category_name CHARACTER VARYING(255), CONSTRAINT PK_tbl_category PRIMARY KEY (category_id) ); CREATE TABLE tbl_product ( product_id BIGSERIAL NOT NULL, product_name CHARACTER VARYING(255), created_at TIMESTAMP, category_id INTEGER, CONSTRAINT PK_tbl_product PRIMARY KEY (product_id) ); ALTER TABLE tbl_product ADD CONSTRAINT tbl_category_tbl_product FOREIGN KEY (category_id) REFERENCES tbl_category (category_id);
MSSQL için SQL kodları:
CREATE TABLE [tbl_category] ( [category_id] INTEGER IDENTITY(0,1) NOT NULL, [category_name] VARCHAR(255), CONSTRAINT [PK_tbl_category] PRIMARY KEY ([category_id]) ) GO CREATE TABLE [tbl_product] ( [product_id] BIGINT IDENTITY(0,1) NOT NULL, [product_name] VARCHAR(255), [created_at] TIMESTAMP, [category_id] INTEGER, CONSTRAINT [PK_tbl_product] PRIMARY KEY ([product_id]) ) GO ALTER TABLE [tbl_product] ADD CONSTRAINT [tbl_category_tbl_product] FOREIGN KEY ([category_id]) REFERENCES [tbl_category] ([category_id]) GO
TEKRARLI ALT SORGU İÇİN ÖRNEK:
10’dan fazla ürün içeren kategorileri ve içerdikleri ürün sayılarını listeleyen bir sorgu yazalım:
Elbette bu basit örneği GROUP BY kullanarak da çözmek mümkün ancak burada amacımız alt-sorgu oluşturmak zorunda kaldığımız bir durumu küçük bir örnekle modellemek.
SELECT *, (SELECT COUNT(*) FROM tbl_product WHERE tbl_product.category_id = tbl_category.category_id ) AS product_number FROM tbl_category WHERE (SELECT COUNT(*) FROM tbl_product WHERE tbl_product.category_id = tbl_category.category_id ) > 10
Burada, aynı alt-sorgu iki kez işletiliyor. Bu bize bir kaç türlü olumsuz dönüş sağlar:
- SQL kodu uzun olacağından, kod okunabilirliği azalır. Uzun sorguların, veritabanı sunucusuna iletilmesi ve anlaşılabilmesi de nispeten yavaştır. Ancak günümüz ağ teknolojilerinde bu hissedilebilir düzeyde olmayacaktır.
- Eğer veritabanı sunucusu bir cache mekanizması kullanmıyorsa, aynı alt sorguyu iki kez çalıştırmak zorunda kalacaktır. Tabi bu arada ana sorgu da stack de kalacağından fazladan bellek tüketimi demektir.
gelelim LATERAL yada CROSS APPLY deyimlerine:
Ayını SQL kodunu LATERAL ile PostgreSQL için yazacak olursak:
TEKRARSIZ ALT SORGU İÇİN ÖRNEKLER:
SELECT *, product_number_by_category.product_number FROM tbl_category, LATERAL (SELECT COUNT(*) as product_number FROM tbl_product WHERE tbl_product.category_id = tbl_category.category_id) as product_number_by_category WHERE product_number_by_category.product_number > 10
Aynı SQL kodunu CROSS APPLY ile MSSQL için yazacak olursak:
SELECT *, product_number_by_category.product_number FROM tbl_category CROSS APPLY (SELECT COUNT(*) as product_number FROM tbl_product WHERE tbl_product.category_id = tbl_category.category_id) as product_number_by_category WHERE product_number_by_category.product_number > 10
Gözlemleyebileceğiniz gibi LATERAL yada CROSS APPLY ile alınan alt sorgular, tek bir kayıt içeriyor olsalar bile ayrı bir tablo gibi davranmaktadırlar. Bu durumda bu ayrı tabloya JOIN yapmamak için de hiç bir sebep yok.