← Kursa Dön
📄 Text · 30 min

Koşullu İfadeler: CASE WHEN, IF, NULLIF

Giriş — SQL'de Karar Verme

Programlama dillerinde if/else ile koşullu mantık kurarsın. SQL'de aynı işi CASE WHEN yapar. Bu, SELECT içinde "eğer şu koşul sağlanıyorsa şu değeri göster" demenin yoludur.

🎯 Analoji: Bir otomatik e-posta sistemi düşün: sipariş durumu "pending" ise "Siparişiniz alındı", "shipped" ise "Kargoya verildi", "delivered" ise "Teslim edildi" mesajı gönder. CASE WHEN tam olarak bu karar mekanizmasıdır.


CASE WHEN — SQL'in IF/ELSE'i

Basit CASE (Eşitlik Kontrolü)

CASE sütun
    WHEN deger1 THEN sonuc1
    WHEN deger2 THEN sonuc2
    ...
    ELSE varsayılan_sonuc
END

-- Sipariş durumunu Türkçeleştir
SELECT order_id, status,
    CASE status
        WHEN 'pending' THEN 'Beklemede'
        WHEN 'processing' THEN 'İşleniyor'
        WHEN 'shipped' THEN 'Kargoda'
        WHEN 'delivered' THEN 'Teslim Edildi'
        WHEN 'cancelled' THEN 'İptal'
        ELSE 'Bilinmiyor'
    END AS durum_turkce
FROM orders;

Searched CASE (Koşullu İfade)

Daha esnek — her WHEN'de farklı koşullar yazabilirsin:

CASE
    WHEN koşul1 THEN sonuc1
    WHEN koşul2 THEN sonuc2
    ...
    ELSE varsayılan_sonuc
END

-- Fiyat kategorileri
SELECT product_name, price,
    CASE
        WHEN price < 100 THEN 'Ekonomik'
        WHEN price < 1000 THEN 'Uygun'
        WHEN price < 10000 THEN 'Orta Segment'
        WHEN price < 50000 THEN 'Premium'
        ELSE 'Lüks'
    END AS fiyat_segmenti
FROM products;

⚠️ Dikkat: CASE WHEN koşulları sırayla değerlendirilir. İlk TRUE olan koşulun sonucu döner ve geri kalanı kontrol edilmez. Bu yüzden koşul sırası önemlidir:

-- ❌ YANLIŞ sıra — her şey "Ucuz" olur
CASE
    WHEN price > 0 THEN 'Ucuz'          -- Her pozitif fiyat buraya düşer!
    WHEN price > 1000 THEN 'Orta'       -- Asla çalışmaz
    WHEN price > 10000 THEN 'Pahalı'    -- Asla çalışmaz
END

-- ✅ DOĞRU sıra — dar koşuldan geniş koşula
CASE
    WHEN price > 10000 THEN 'Pahalı'
    WHEN price > 1000 THEN 'Orta'
    WHEN price > 0 THEN 'Ucuz'
END

CASE WHEN ile NULL Kontrolü

SELECT product_name,
    CASE
        WHEN stock_quantity IS NULL THEN 'Bilgi Yok'
        WHEN stock_quantity = 0 THEN 'Tükendi'
        WHEN stock_quantity < 10 THEN 'Son Birkaç Adet!'
        WHEN stock_quantity < 50 THEN 'Sınırlı Stok'
        ELSE 'Stokta'
    END AS stok_durumu
FROM products;

WHERE'de CASE

-- Koşullu filtreleme
SELECT * FROM orders
WHERE status = CASE 
    WHEN DAYOFWEEK(NOW()) IN (1, 7) THEN 'pending'  -- Hafta sonu: bekleyenler
    ELSE 'processing'                                  -- Hafta içi: işlenenler
END;

ORDER BY'da CASE

-- Özel sıralama: önce kritik stoklar
SELECT product_name, stock_quantity FROM products
ORDER BY 
    CASE 
        WHEN stock_quantity = 0 THEN 1      -- En üste
        WHEN stock_quantity < 10 THEN 2     -- İkinci
        WHEN stock_quantity < 50 THEN 3     -- Üçüncü
        ELSE 4                               -- En alta
    END ASC,
    stock_quantity ASC;

UPDATE'te CASE

-- Toplu fiyat güncelleme: kategoriye göre farklı zam
UPDATE products 
SET price = CASE
    WHEN category_id IN (1, 2, 3) THEN ROUND(price * 1.10, 2)  -- Elektronik: %10
    WHEN category_id IN (4, 5, 6) THEN ROUND(price * 1.05, 2)  -- Giyim: %5
    WHEN category_id = 7 THEN ROUND(price * 1.03, 2)            -- Kitap: %3
    ELSE price  -- Değiştirme
END
WHERE is_active = TRUE;

IF() Fonksiyonu — İki Seçenekli Kısa Yol

MySQL'e özel basit if/else:

IF(koşul, doğruysa_değer, yanlışsa_değer)

-- Boolean sütunu okunabilir hale getir
SELECT product_name,
       IF(is_active, 'Aktif', 'Pasif') AS durum
FROM products;

-- Stok kontrolü
SELECT product_name,
       IF(stock_quantity > 0, 'Stokta', 'Tükendi') AS stok
FROM products;

-- NULL kontrolü
SELECT first_name,
       IF(phone IS NOT NULL, phone, 'Belirtilmemiş') AS telefon
FROM customers;

CASE vs IF karşılaştırması:

-- IF: Sadece 2 seçenek (ternary operatör gibi)
SELECT IF(price > 1000, 'Pahalı', 'Uygun') FROM products;

-- CASE: Çoklu seçenek (if/elif/else gibi)
SELECT CASE
    WHEN price > 10000 THEN 'Çok Pahalı'
    WHEN price > 1000 THEN 'Pahalı'
    ELSE 'Uygun'
END FROM products;

💡 İpucu: 2 seçenek varsa IF(), 3+ seçenek varsa CASE WHEN kullan. CASE WHEN SQL standardıdır ve her yerde çalışır; IF() MySQL'e özeldir.


NULLIF — Eşitse NULL Yap

NULLIF'i daha önce gördük ama CASE WHEN bağlamında tekrar ele alalım:

-- NULLIF(a, b) → a = b ise NULL, değilse a
SELECT NULLIF(10, 10);   -- NULL
SELECT NULLIF(10, 5);    -- 10

-- Aslında CASE WHEN'in kısaltması:
-- NULLIF(a, b) = CASE WHEN a = b THEN NULL ELSE a END

-- Sıfıra bölme koruması (en yaygın kullanım)
SELECT order_id,
       total_amount,
       item_count,
       ROUND(total_amount / NULLIF(item_count, 0), 2) AS avg_item_price
FROM (
    SELECT o.order_id, o.total_amount, COUNT(oi.item_id) AS item_count
    FROM orders o
    LEFT JOIN order_items oi ON o.order_id = oi.order_id
    GROUP BY o.order_id, o.total_amount
) AS order_summary;

Gerçek Dünya Örneği — E-Ticaret Dashboard

-- Sipariş dashboard'u — her sipariş için detaylı durum bilgisi
SELECT 
    o.order_id,
    CONCAT(c.first_name, ' ', c.last_name) AS musteri,
    DATE_FORMAT(o.order_date, '%d.%m.%Y') AS tarih,
    CONCAT('₺', FORMAT(o.total_amount, 2)) AS tutar,
    -- Durum badge'i
    CASE o.status
        WHEN 'pending' THEN '🟡 Beklemede'
        WHEN 'processing' THEN '🔵 İşleniyor'
        WHEN 'shipped' THEN '🟣 Kargoda'
        WHEN 'delivered' THEN '🟢 Teslim'
        WHEN 'cancelled' THEN '🔴 İptal'
    END AS durum,
    -- Aciliyet
    CASE
        WHEN o.status = 'pending' AND DATEDIFF(NOW(), o.order_date) > 3 
            THEN '⚠️ ACİL'
        WHEN o.status = 'pending' AND DATEDIFF(NOW(), o.order_date) > 1 
            THEN '⏳ Takipte'
        WHEN o.status IN ('delivered', 'cancelled') 
            THEN '✅ Kapandı'
        ELSE '📋 Normal'
    END AS aciliyet,
    -- Geçen süre
    CONCAT(DATEDIFF(NOW(), o.order_date), ' gün') AS gecen_sure
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id
ORDER BY 
    CASE o.status
        WHEN 'pending' THEN 1
        WHEN 'processing' THEN 2
        WHEN 'shipped' THEN 3
        WHEN 'delivered' THEN 4
        WHEN 'cancelled' THEN 5
    END,
    o.order_date ASC;

Sıkça Yapılan Hatalar

  1. CASE WHEN koşul sırası: Geniş koşuldan dar koşula gidersen ilk koşul her şeyi yakalar. Dar→geniş sıra kullan.

  2. ELSE unutmak: ELSE olmadan hiçbir koşula uymayan satırlar NULL döner. Genellikle ELSE yazmak iyi pratiktir.

  3. END unutmak: Her CASE bir END ile kapatılmalıdır. Unutursan syntax hatası alırsın.

  4. IF() ile CASE karıştırmak: IF() iki seçenekli, CASE çoklu seçenekli. İkisini iç içe yazmak kodu okunamaz hale getirir.

  5. SELECT dışında kullanmayı bilmemek: CASE WHEN sadece SELECT'te değil, WHERE, ORDER BY, UPDATE SET, INSERT VALUES, HAVING — neredeyse her yerde kullanılabilir.


Özet

  • CASE WHEN SQL'in if/else mekanizmasıdır — çoklu koşullu mantık kurar

  • Basit CASE (CASE sütun WHEN değer) eşitlik kontrolü, Searched CASE (CASE WHEN koşul) esnek karşılaştırma yapar

  • CASE koşulları sırayla değerlendirilir — dar koşuldan geniş koşula yaz

  • IF() MySQL'e özel, 2 seçenekli kısa yol. 3+ seçenekte CASE kullan

  • NULLIF iki değer eşitse NULL döndürür — sıfıra bölme koruması

  • CASE WHEN SELECT, WHERE, ORDER BY, UPDATE, INSERT — her yerde çalışır

  • ELSE yazmayı unutma — yoksa uyumsuz satırlar NULL döner