Window Frame ROWS vs RANGE di SQL: Apa Bedanya (2026)
TL;DR
Window frame nentuin baris mana aja yang dihitung window function di tiap baris. ROWS ngitung baris fisik satu per satu, sedangkan RANGE nge-grup semua baris yang nilai ORDER BY-nya sama jadi satu. Default window frame di SQL pakai RANGE, dan ini sering bikin running total salah kalau ada nilai kembar seperti tanggal yang sama.
Window frame nentuin baris mana aja yang dihitung window function di tiap baris. ROWS ngitung baris fisik satu per satu, RANGE nge-grup semua baris yang nilainya sama jadi satu.
Beda ini kelihatan sepele, tapi sering bikin running total salah tanpa ketahuan. Terutama kalau ada tanggal kembar.
Di sini aku jelasin bedanya, kapan pakai yang mana, dan kenapa default SQL bisa ngasih angka yang bukan kamu maksud.
Apa itu window frame di SQL?
Window frame adalah subset baris yang dihitung window function di tiap baris. Buat running total, frame nentuin baris mana aja yang dijumlah sampai baris sekarang. Frame ditulis di dalam OVER pakai klausa ROWS atau RANGE. Tanpa frame eksplisit, SQL pakai default yang belum tentu sesuai maumu.
Kalau kamu belum akrab sama window function secara umum, cek dulu glossary window function biar dasarnya kepegang.
Apa bedanya ROWS dan RANGE?
ROWS ngitung baris fisik satu per satu. ROWS BETWEEN 2 PRECEDING AND CURRENT ROW ngambil tepat tiga baris. RANGE nge-grup semua baris yang nilai ORDER BY-nya sama jadi satu posisi. Kalau ada tiga baris bertanggal sama, RANGE nganggep mereka satu.
Bedanya baru muncul kalau ada nilai kembar di kolom ORDER BY. Kalau semua nilainya unik, ROWS dan RANGE ngasih hasil sama.
| Aspek | ROWS | RANGE |
|---|---|---|
| Cara hitung | Baris fisik | Berdasarkan nilai |
| Nilai kembar | Dihitung terpisah | Digabung jadi satu |
| Running total per baris | Naik bertahap | Bisa lompat |
| Default frame | Bukan | Iya |
Kenapa default SQL bisa bikin running total salah?
Kalau ada ORDER BY di dalam OVER tapi frame nggak ditulis, default-nya RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW. Artinya semua baris dengan nilai ORDER BY sama dihitung bareng. Banyak orang ngira default-nya ROWS, dan di sinilah angkanya melenceng.
-- Default (RANGE): dua baris tanggal sama nunjukin total yang sama
SELECT id, tanggal, total,
SUM(total) OVER (ORDER BY tanggal) AS running
FROM penjualan;
Di data dengan dua transaksi bertanggal 1 Maret, baris pertama dan kedua sama-sama nunjukin 150.000, bukan 100.000 lalu 150.000. RANGE ngeborong dua transaksi tanggal itu ke tiap barisnya.
Kalau yang kamu mau running total naik per baris, pakai ROWS secara eksplisit.
SELECT id, tanggal, total,
SUM(total) OVER (
ORDER BY tanggal
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS running
FROM penjualan;
Kapan pakai ROWS?
Pakai ROWS kalau kamu mau ngitung sejumlah baris fisik yang pasti. Running total yang naik per transaksi, moving average tiga baris terakhir, atau ngambil beberapa baris sebelum dan sesudah. ROWS ngasih kontrol persis atas jumlah baris tanpa peduli nilai kembar.
-- Moving average 3 baris terakhir
SELECT id, tanggal, total,
AVG(total) OVER (
ORDER BY tanggal
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
) AS rata_3_baris
FROM penjualan;
Buat kebanyakan kasus laporan sehari-hari, ROWS yang kamu mau. Dia jelas dan nggak ada kejutan dari nilai kembar.
Kapan pakai RANGE?
Pakai RANGE kalau kamu memang mau semua baris dengan nilai sama dihitung sebagai satu kesatuan. Contohnya total kumulatif per hari di mana semua transaksi satu tanggal harus nunjukin angka yang sama. RANGE juga kepakai buat frame berbasis rentang nilai, seperti tujuh hari ke belakang.
-- Total 7 hari terakhir pakai rentang tanggal (PostgreSQL)
SELECT id, tanggal, total,
SUM(total) OVER (
ORDER BY tanggal
RANGE BETWEEN INTERVAL '7 days' PRECEDING AND CURRENT ROW
) AS total_7_hari
FROM penjualan;
Frame RANGE dengan interval waktu ini kuat, tapi dukungannya beda tiap database. PostgreSQL dan Oracle paling lengkap. Cek dokumentasi database kamu sebelum pakai.
Contoh kasus: running total penjualan toko_berkah
Toko_berkah pernah minta laporan omzet berjalan per transaksi. Datanya 5 transaksi dalam 3 hari, dengan dua hari yang punya lebih dari satu transaksi.
Dari dataset ngulikdata, versi default RANGE bikin dua transaksi di 1 Maret sama-sama nunjukin 150.000. Pemilik toko bingung kenapa transaksi pertama seharga 100.000 tapi running total-nya udah 150.000. Setelah diganti ROWS, angkanya naik bertahap dan masuk akal: 100.000 lalu 150.000.
Perbedaan satu kata, ROWS versus RANGE, yang misahin laporan yang bener dari yang bikin salah paham. Buat lanjut belajar ngerangkum data, cek GROUP BY dan HAVING.
Kesalahan umum window frame
Ngandelin default tanpa tau itu RANGE. Kalau ada nilai kembar, hasilnya bukan running total yang naik per baris. Tulis frame eksplisit biar nggak nebak-nebak.
Pakai ROWS padahal butuh gabung nilai sama. Kalau kamu memang mau semua transaksi satu hari nunjukin total harian yang sama, ROWS malah misahin mereka. Di kasus ini RANGE yang bener.
Lupa ORDER BY di dalam OVER. Tanpa ORDER BY, frame default-nya semua baris di partisi, dan running total nggak kebentuk sama sekali. Selalu sebut ORDER BY buat perhitungan berurutan.
FAQ
Apa itu window frame di SQL?
Window frame nentuin baris mana aja yang dihitung window function di tiap baris. Ditulis pakai ROWS atau RANGE di dalam OVER. Tanpa frame eksplisit, SQL pakai default yang belum tentu sesuai maumu.
Apa bedanya ROWS dan RANGE?
ROWS ngitung baris fisik satu per satu. RANGE nge-grup semua baris yang nilai ORDER BY-nya sama jadi satu. Bedanya baru kelihatan kalau ada nilai kembar seperti tanggal yang sama.
Apa default window frame kalau nggak ditulis?
Kalau ada ORDER BY tapi frame nggak ditulis, default-nya RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW. Semua baris dengan nilai sama dihitung bareng. Banyak yang kaget karena ngira default-nya ROWS.
Penutup
ROWS dan RANGE cuma beda satu kata, tapi hasilnya bisa jauh beda kalau ada nilai kembar. ROWS ngitung baris fisik, RANGE nge-grup nilai sama, dan default SQL pakai RANGE. Buat running total yang naik per baris, tulis ROWS secara eksplisit.
Mau latihan window function di dataset asli? Kulik di NgulikSQL, editor SQL siap pakai tanpa install.
Lanjut baca: SQL date bucketing buat ngelompokkan data per rentang waktu, dan dokumentasi resmi window function PostgreSQL.
Mau praktek langsung? Mulai latihan SQL gratis
Latihan interaktif, langsung di browser.
Artikel terkait
Composite Index di SQL: Cara Kerja dan Urutan Kolom
Composite index itu index atas beberapa kolom sekaligus. Urutan kolomnya nentuin query mana yang kebantu, lewat aturan leftmost prefix.
Menghitung Stickiness (DAU/MAU) di SQL
Stickiness ngukur seberapa sering user balik lagi. Ini cara hitung DAU, MAU, dan rasio stickiness pakai SQL, plus contoh aplikasi UMKM.
Menghitung DAU dan MAU dengan SQL
DAU dan MAU dua metrik wajib buat produk digital. Ini cara hitungnya pakai SQL, lengkap query DISTINCT, per bulan, sampai rasio stickiness.