Ana içeriğe geç
Kesit SQL
İleri · Pencere Fonksiyonları

İleri pencere çerçeveleri: ROWS, RANGE, GROUPS ve EXCLUDE

Eşitliklerin pencereyi nasıl etkilediği, değer aralığına göre pencere, SQL türlerine göre destek.

Uygulamada aç, 7 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ç.

Üç çerçeve birimi

BirimPencereyi neye göre sayar?
ROWSFiziksel satır sayısı
RANGEORDER BY değerinin aralığı (eşit değerler hep birlikte)
GROUPSEşit değer gruplarının sayısı

ROWS ile RANGE farkı: eşitlikler

Aynı fiyattaki ürünlerde yürüyen toplam:

SELECT name, price,
       SUM(price) OVER (ORDER BY price ROWS  BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS rows_toplam,
       SUM(price) OVER (ORDER BY price RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS range_toplam
FROM products
WHERE category IN ('Kitap', 'Hediye')
ORDER BY price, name;

RANGE, aynı fiyattaki tüm satırları “şu ana kadar” sayar; bu yüzden eşit değerli satırlar aynı toplamı gösterir. ORDER BY yazıp çerçeve yazmazsan varsayılan RANGE'dir; yürüyen toplamda beklenmedik sonuç görürsen nedeni budur.

Değer aralığına göre pencere

“Son 7 günlük sipariş sayısı” gibi takvime dayalı pencerelerde satır sayısı değil tarih aralığı gerekir (bazı günlerde hiç sipariş yoksa ROWS yanlış olur):

-- PostgreSQL, Oracle, MySQL 8
SELECT order_date, gunluk,
       SUM(gunluk) OVER (ORDER BY order_date
                         RANGE BETWEEN INTERVAL '6' DAY PRECEDING AND CURRENT ROW) AS son7
FROM gunluk_siparis;

-- BigQuery: RANGE yalnızca sayısal; tarihi gün numarasına çevir
SUM(gunluk) OVER (ORDER BY UNIX_DATE(order_date) RANGE BETWEEN 6 PRECEDING AND CURRENT ROW)

-- SQL Server: RANGE yalnızca UNBOUNDED / CURRENT ROW destekler;
-- takvim tablosuyla eksik günleri doldurup ROWS BETWEEN 6 PRECEDING kullanılır.

SQLite'ta da sayısal RANGE vardır; tarihi gün numarasına (julianday) çevirerek deneyelim:

WITH g AS (
  SELECT order_date, COUNT(*) AS gunluk
  FROM orders
  WHERE order_date >= '2024-12-01'
  GROUP BY order_date
)
SELECT order_date, gunluk,
       SUM(gunluk) OVER (ORDER BY julianday(order_date) RANGE BETWEEN 6 PRECEDING AND CURRENT ROW) AS son7
FROM g
ORDER BY order_date;

GROUPS ve EXCLUDE

SELECT name, price,
       SUM(price) OVER (ORDER BY price GROUPS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS komsu_gruplar,
       AVG(price) OVER (PARTITION BY category ORDER BY price
                        ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
                        EXCLUDE CURRENT ROW) AS digerlerinin_ort
FROM products
WHERE category = 'Kitap'
ORDER BY price;

EXCLUDE CURRENT ROW satırın kendisini pencereden çıkarır: “bu ürün kategorideki diğer ürünlerin ortalamasından ne kadar farklı?” sorusu için idealdir. Diğer seçenekler: EXCLUDE GROUP, EXCLUDE TIES, EXCLUDE NO OTHERS.

SQL türüROWSRANGE (değer aralığı)GROUPSEXCLUDE
PostgreSQL 11+✓✓ (interval dahil)✓✓
Oracle✓✓21c+21c+
MySQL 8✓✓——
SQL Server✓yalnızca UNBOUNDED/CURRENT ROW——
BigQuery✓yalnızca sayısal——
SQLite 3.28+✓✓ (sayısal)✓✓
Alıştırmalara geç (7)