Ana içeriğe geç
Kesit SQL
İleri · Mülakat Hazırlığı

Mülakat kalıbı: zaman pencereleri, büyüme ve “son 30 gün”

Aydan aya büyüme, kümülatif toplam, hareketli pencere ve kayan “son N gün” sorularında doğru çerçeve.

Uygulamada aç, 6 alıştırmayı çözÜcretsiz, hesap gerekmez, kurulum yok.

Bu sayfa dersin okuma sürümüdür. Metin bir kutuyu çalıştırmanı ya da adıma geçmeni söylüyorsa dersi uygulamada aç.

Soru

Görüşmeci“Her ay için teslim edilen ciroyu, bir önceki aya göre büyümeyi ve yılbaşından bu yana kümülatif ciroyu getir.” Takip: “Her gün için son 7 günün cirosu nedir? Sipariş olmayan günler de görünmeli.”

Önce netleştir

Kod yazmadan önce sorulacak sorular. Her biri farklı bir sorguya götürür; sormamak en sık puan kaybıdır.

Yaklaşım

  1. Önce aylık (ya da günlük) toplam tablosunu kur.
  2. LAG ile bir önceki dönemi getir, farkı yüzdeye çevir.
  3. SUM OVER (PARTITION BY yıl ORDER BY ay) ile yılbaşından bu yana kümülatif.
  4. Boş günler için önce takvim üret, sonra LEFT JOIN; çerçeveyi ROWS BETWEEN 6 PRECEDING AND CURRENT ROW yap.

Çözüm 1: aylık tablo + LAG + kümülatif

WITH a AS (
  SELECT strftime('%Y', o.order_date) AS yil, strftime('%Y-%m', o.order_date) AS ay,
         SUM(oi.quantity * oi.unit_price * (1 - oi.discount)) AS ciro
  FROM orders o JOIN order_items oi ON oi.order_id = o.order_id
  WHERE o.status = 'delivered'
  GROUP BY strftime('%Y', o.order_date), strftime('%Y-%m', o.order_date)
)
SELECT ay, ROUND(ciro) AS ciro,
       ROUND(100.0 * (ciro - LAG(ciro) OVER (ORDER BY ay)) / LAG(ciro) OVER (ORDER BY ay), 1) AS buyume,
       ROUND(SUM(ciro) OVER (PARTITION BY yil ORDER BY ay ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)) AS ytd
FROM a
WHERE ay >= '2024-01'
ORDER BY ay;

Çözüm 2: takvim + LEFT JOIN + hareketli pencere

WITH RECURSIVE takvim(gun) AS (
  SELECT '2024-12-01' UNION ALL SELECT date(gun, '+1 day') FROM takvim WHERE gun < '2024-12-31'
),
g AS (
  SELECT o.order_date AS gun, SUM(oi.quantity * oi.unit_price * (1 - oi.discount)) AS ciro
  FROM orders o JOIN order_items oi ON oi.order_id = o.order_id
  WHERE o.status = 'delivered' AND o.order_date >= '2024-11-25'
  GROUP BY o.order_date
)
SELECT t.gun, ROUND(COALESCE(g.ciro, 0)) AS ciro,
       ROUND(SUM(COALESCE(g.ciro, 0)) OVER (ORDER BY t.gun ROWS BETWEEN 6 PRECEDING AND CURRENT ROW)) AS son7
FROM takvim t LEFT JOIN g ON g.gun = t.gun
ORDER BY t.gun;

İkinci çözümdeki takvim adımı çok önemlidir: boş günler tabloda olmazsa “6 PRECEDING” altı satır öncesine, yani belki on gün öncesine bakar. Ayrıca ilk 6 gün eksik pencereyle hesaplanır; bunu görüşmeciye söylemek ya da takvimi 6 gün geriden başlatmak gerekir.

Sınır durumları

DurumNe olur?
Önceki dönem yokLAG NULL döner; büyüme NULL kalmalı, 0 değil
Önceki dönem 0Sıfıra bölme: NULLIF(LAG(...), 0)
Boş günlerTakvim olmadan pencere yanlış genişler
Varsayılan çerçeveORDER BY olan SUM OVER varsayılanı RANGE'dir; aynı tarihli satırlar birlikte toplanır

Takip soruları

Görüşmeci neye bakıyor?Boş dönemleri ve pencere çerçevesini kendiliğinden düşünmen; büyümede NULL ile 0 farkını gözetmen.
Alıştırmalara geç (6)