← Kursa Dön
📄 Text · 30 min

WITH ROLLUP ve GROUPING

Giriş — Rapordaki Toplam Satırı

Excel'de bir pivot tablo oluşturduğunda, her grubun altında otomatik ara toplam ve en altta genel toplam satırı olur. SQL'de bunu WITH ROLLUP yapar.

🎯 Analoji: Bir mağaza zincirinin satış raporu düşün. Her şubenin satışları listeleniyor, ama raporun sonunda "TÜM ŞUBELER TOPLAMI" satırı da olmalı. WITH ROLLUP bu toplam satırını otomatik ekler.


WITH ROLLUP — Hiyerarşik Toplamlar

-- Şehir bazlı sipariş sayısı + GENEL TOPLAM
SELECT 
    COALESCE(city, 'GENEL TOPLAM') AS city,
    COUNT(*) AS order_count,
    ROUND(SUM(total_amount), 2) AS revenue
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id
GROUP BY city WITH ROLLUP;
+--------------+-------------+-----------+
| city         | order_count | revenue   |
+--------------+-------------+-----------+
| Ankara       | 3           | 66219.96  |
| Antalya      | 1           | 8999.99   |
| Bursa        | 1           | 899.99    |
| İstanbul     | 4           | 58349.95  |
| İzmir        | 1           | 45299.98  |
| GENEL TOPLAM | 10          | 179769.87 |
+--------------+-------------+-----------+

Son satır (GENEL TOPLAM) MySQL tarafından otomatik eklendi.

Çoklu Sütunla ROLLUP

-- Yıl → Ay hiyerarşisi ile ROLLUP
SELECT 
    COALESCE(CAST(YEAR(order_date) AS CHAR), 'TOPLAM') AS year,
    COALESCE(CAST(MONTH(order_date) AS CHAR), 'Alt Toplam') AS month,
    COUNT(*) AS orders,
    ROUND(SUM(total_amount), 2) AS revenue
FROM orders
GROUP BY YEAR(order_date), MONTH(order_date) WITH ROLLUP;
+--------+-----------+--------+-----------+
| year   | month     | orders | revenue   |
+--------+-----------+--------+-----------+
| 2024   | 1         | 5      | 167449.93 |
| 2024   | 2         | 5      | 12319.94  |
| 2024   | Alt Toplam| 10     | 179769.87 |  ← 2024 yılı toplamı
| TOPLAM | Alt Toplam| 10     | 179769.87 |  ← Genel toplam
+--------+-----------+--------+-----------+

ROLLUP sağdan sola hiyerarşik toplamlar oluşturur:

  1. Önce her yıl-ay kombinasyonu

  2. Sonra her yılın toplamı (ay = NULL)

  3. En son genel toplam (yıl ve ay = NULL)


GROUPING() Fonksiyonu — ROLLUP Satırlarını Tanıma

ROLLUP'ın eklediği toplam satırlarında gruplama sütunu NULL olur. Ama verinin kendisi de NULL olabilir — nasıl ayırt ederiz?

-- GROUPING() fonksiyonu: ROLLUP tarafından eklenen NULL ise 1 döner
SELECT 
    CASE 
        WHEN GROUPING(city) = 1 THEN '*** GENEL TOPLAM ***'
        ELSE COALESCE(city, 'Şehir Belirtilmemiş')
    END AS city,
    COUNT(*) AS order_count,
    ROUND(SUM(total_amount), 2) AS revenue
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id
GROUP BY city WITH ROLLUP;

GROUPING(sütun) değerleri:

  • 0 = Normal grup satırı (gerçek veri)

  • 1 = ROLLUP tarafından oluşturulan toplam satırı

Çok Sütunlu GROUPING

SELECT 
    CASE WHEN GROUPING(c.city) = 1 THEN 'TÜM ŞEHİRLER' ELSE c.city END AS city,
    CASE WHEN GROUPING(o.status) = 1 THEN 'TÜM DURUMLAR' ELSE o.status END AS status,
    COUNT(*) AS order_count,
    ROUND(SUM(o.total_amount), 2) AS revenue
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id
GROUP BY c.city, o.status WITH ROLLUP;

ROLLUP vs Manuel UNION Toplam

ROLLUP olmadan aynı sonucu UNION ile de üretebilirsin ama daha zahmetli:

-- ❌ Manuel — 2 ayrı sorgu + UNION
SELECT city, COUNT(*) AS cnt, SUM(total_amount) AS rev
FROM orders o JOIN customers c ON o.customer_id = c.customer_id
GROUP BY city
UNION ALL
SELECT 'TOPLAM', COUNT(*), SUM(total_amount)
FROM orders;

-- ✅ WITH ROLLUP — tek sorgu, otomatik
SELECT COALESCE(city, 'TOPLAM') AS city, COUNT(*), ROUND(SUM(total_amount), 2)
FROM orders o JOIN customers c ON o.customer_id = c.customer_id
GROUP BY city WITH ROLLUP;

Gerçek Dünya Örneği — Hiyerarşik Satış Raporu

-- Kategori → Ürün hiyerarşik satış raporu
SELECT 
    CASE 
        WHEN GROUPING(cat.category_name) = 1 THEN '=== GENEL TOPLAM ==='
        WHEN GROUPING(p.product_name) = 1 THEN CONCAT('-- ', cat.category_name, ' Toplamı --')
        ELSE p.product_name
    END AS item,
    COALESCE(SUM(oi.quantity), 0) AS units_sold,
    ROUND(COALESCE(SUM(oi.quantity * oi.unit_price), 0), 2) AS revenue
FROM categories cat
LEFT JOIN products p ON cat.category_id = p.category_id
LEFT JOIN order_items oi ON p.product_id = oi.product_id
GROUP BY cat.category_name, p.product_name WITH ROLLUP
HAVING COALESCE(SUM(oi.quantity), 0) > 0 OR GROUPING(p.product_name) = 1;

Sıkça Yapılan Hatalar

  1. ROLLUP satırındaki NULL'u veri NULL'uyla karıştırmak: GROUPING() fonksiyonu ile ayırt et.

  2. ORDER BY ile ROLLUP: MySQL'de WITH ROLLUP kullanırken ORDER BY eklemek toplam satırların konumunu bozabilir. Dikkatli kullan.

  3. ROLLUP'ı her raporda kullanmak: Uygulama katmanında toplam hesaplamak çoğu zaman daha pratik. ROLLUP, doğrudan SQL raporları ve BI araçları için idealdir.

📝 PostgreSQL Notu: PostgreSQL'de ROLLUP, CUBE ve GROUPING SETS daha esnektir: ``sql GROUP BY ROLLUP(city, status) -- Hiyerarşik GROUP BY CUBE(city, status) -- Tüm kombinasyonlar GROUP BY GROUPING SETS ((city), (status), ()) -- Belirli kombinasyonlar ``


Özet

  • WITH ROLLUP GROUP BY sonuçlarına otomatik ara toplam ve genel toplam satırları ekler

  • ROLLUP sağdan sola hiyerarşik toplamlar oluşturur

  • GROUPING(sütun) fonksiyonu ROLLUP tarafından eklenen satırları (1) normal satırlardan (0) ayırt eder

  • Çoklu sütunla ROLLUP, her hiyerarşi seviyesi için ara toplam üretir

  • Excel pivot tablo benzeri raporlar için çok kullanışlı

  • PostgreSQL'de CUBE ve GROUPING SETS ek esneklik sağlar