← Kursa Dön
📄 Text · 25 min

FROM'da Subquery (Derived Table)

Giriş — Geçici Tablo Oluşturmadan Ara Sonuçlar

FROM'da subquery kullanmak, sorgu sonucunu geçici bir tablo gibi kullanmana olanak tanır. Buna derived table (türetilmiş tablo) denir. Karmaşık hesaplamaları adımlara bölerek daha okunabilir sorgular yazmanı sağlar.


Temel Kullanım

-- Müşteri sipariş istatistiklerini hesapla, sonra filtrele
SELECT customer_name, order_count, total_spent
FROM (
    SELECT 
        CONCAT(c.first_name, ' ', c.last_name) AS customer_name,
        COUNT(o.order_id) AS order_count,
        COALESCE(SUM(o.total_amount), 0) AS total_spent
    FROM customers c
    LEFT JOIN orders o ON c.customer_id = o.customer_id
    GROUP BY c.customer_id, c.first_name, c.last_name
) AS customer_stats        -- ← Alias ZORUNLU!
WHERE total_spent > 5000
ORDER BY total_spent DESC;

Neden derived table? WHERE'da aggregate sonucu filtrelemek normalde HAVING ile yapılır ama bazen derived table daha okunabilir. Ayrıca birden fazla aggregate sonucunu kullanarak yeni hesaplamalar yapabilirsin.


İç İçe Hesaplamalar

-- Ortalama sipariş tutarının ortalaması (iç içe aggregate)
SELECT ROUND(AVG(avg_order), 2) AS overall_avg_order
FROM (
    SELECT customer_id, AVG(total_amount) AS avg_order
    FROM orders
    GROUP BY customer_id
) AS customer_avgs;

-- En yüksek müşteri bazlı gelirle en düşük arasındaki fark
SELECT 
    MAX(total_spent) AS max_customer_revenue,
    MIN(total_spent) AS min_customer_revenue,
    MAX(total_spent) - MIN(total_spent) AS revenue_gap
FROM (
    SELECT customer_id, SUM(total_amount) AS total_spent
    FROM orders
    GROUP BY customer_id
) AS customer_revenues;

Birden Fazla Derived Table

-- Top müşteriler vs ortalama karşılaştırması
SELECT 
    cs.customer_name,
    cs.total_spent,
    avgs.overall_avg,
    cs.total_spent - avgs.overall_avg AS diff_from_avg
FROM (
    SELECT CONCAT(c.first_name, ' ', c.last_name) AS customer_name,
           c.customer_id,
           SUM(o.total_amount) AS total_spent
    FROM customers c
    INNER JOIN orders o ON c.customer_id = o.customer_id
    GROUP BY c.customer_id, c.first_name, c.last_name
) AS cs
CROSS JOIN (
    SELECT AVG(total_amount) AS overall_avg FROM orders
) AS avgs
WHERE cs.total_spent > avgs.overall_avg;

Derived Table vs CTE

Derived table iç içe yazıldığında okunması zorlaşır. CTE (Common Table Expression — B12'de göreceğiz) daha okunabilir bir alternatiftir:

-- Derived table (iç içe)
SELECT * FROM (SELECT * FROM (SELECT ...) AS t1) AS t2;

-- CTE (sıralı, okunabilir) — B12'de detaylı göreceğiz
WITH customer_stats AS (SELECT ...),
     category_stats AS (SELECT ...)
SELECT * FROM customer_stats JOIN category_stats ON ...;

Özet

  • Derived table = FROM'da subquery, geçici tablo gibi davranır

  • Alias vermek zorunludur (AS isim)

  • İç içe aggregate hesaplamalar için idealdir

  • Birden fazla derived table CROSS JOIN ile birleştirilebilir

  • Karmaşık derived table'lar CTE ile daha okunabilir yazılabilir