Fungsi NTH_VALUE di SQL untuk Ambil Nilai ke-N (2026)
TL;DR
NTH_VALUE adalah window function SQL yang ngambil nilai dari baris ke-N dalam sebuah jendela data, misalnya nilai transaksi ke-3 tiap pelanggan. Fungsi ini sering ngasih hasil NULL karena frame default-nya cuma ngelihat dari baris awal sampai baris sekarang. Buat ngambil nilai ke-N dari seluruh grup, tambahin ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING di klausa OVER.
NTH_VALUE adalah window function SQL yang ngambil nilai dari baris ke-N dalam sebuah jendela data, misalnya nilai transaksi ke-3 tiap pelanggan.
FIRST_VALUE ngambil yang pertama, LAST_VALUE yang terakhir. NTH_VALUE ngasih kamu yang mana aja di antaranya.
Yang bikin fungsi ini sering salah: frame default-nya nyembunyiin sebagian data, jadi hasilnya NULL padahal datanya ada. Di bawah ini cara pakainya yang bener plus jebakan frame-nya.
Apa itu NTH_VALUE di SQL?
NTH_VALUE adalah window function yang balikin nilai dari baris ke-N di dalam window frame. Kamu kasih dua argumen: kolom yang mau diambil dan posisi angka ke berapa. Fungsi ini kepake buat ngebandingin baris tertentu, kayak nilai belanja ke-2 tiap pelanggan, tanpa mecah query jadi banyak subquery.
Dia bagian dari keluarga window function yang sama kayak LAG dan LEAD dan RANK. Bedanya, NTH_VALUE fokus ke posisi absolut di dalam grup.
Catatan penting soal dukungan. NTH_VALUE ada di PostgreSQL, MySQL 8.0, Oracle, dan BigQuery. Tapi SQL Server dan SQLite nggak punya.
Sintaks dan cara kerja NTH_VALUE
Bentuk dasarnya:
NTH_VALUE(kolom, n) OVER (
PARTITION BY grup
ORDER BY urutan
ROWS BETWEEN ... AND ...
)
Tiga bagian penting:
- kolom: nilai apa yang mau diambil.
- n: posisi baris ke berapa. Mulai dari 1.
- frame: rentang baris yang dilihat. Ini yang paling sering bikin masalah.
PARTITION BY bikin hitungan mulai ulang tiap ganti grup. ORDER BY nentuin siapa baris pertama, kedua, dan seterusnya. Tanpa ORDER BY, posisi ke-N nggak punya arti.
Kenapa hasil NTH_VALUE sering NULL?
Ini jebakan paling umum. Kalau kamu nggak nulis klausa frame, SQL pakai default RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW. Artinya, tiap baris cuma ngelihat dari awal grup sampai baris itu sendiri. Jadi NTH_VALUE(nilai, 3) balikin NULL sampai baris ke-3 kelihatan.
Contoh yang salah:
SELECT
pelanggan_id,
tanggal,
NTH_VALUE(nilai, 2) OVER (
PARTITION BY pelanggan_id
ORDER BY tanggal
) AS transaksi_kedua
FROM transaksi;
Baris pertama tiap pelanggan bakal NULL, karena baris ke-2 belum masuk frame. Ini yang bikin orang bingung, ngira fungsinya rusak.
Perbaikannya: buka frame-nya ke seluruh grup.
SELECT
pelanggan_id,
tanggal,
nilai,
NTH_VALUE(nilai, 2) OVER (
PARTITION BY pelanggan_id
ORDER BY tanggal
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) AS transaksi_kedua
FROM transaksi
ORDER BY pelanggan_id, tanggal;
Sekarang tiap baris ngelihat seluruh grup, jadi nilai transaksi ke-2 muncul konsisten. Soal frame ini lebih dalam ada di window frame ROWS vs RANGE.
NTH_VALUE vs FIRST_VALUE vs LAST_VALUE
Tiganya satu keluarga, beda posisi yang diambil.
| Fungsi | Ngambil apa | Butuh frame lebar? |
|---|---|---|
| FIRST_VALUE | Nilai baris pertama | Nggak, default udah bener |
| NTH_VALUE(kolom, n) | Nilai baris ke-N | Ya, kalau N di depan |
| LAST_VALUE | Nilai baris terakhir | Ya, selalu |
FIRST_VALUE aman pakai default, karena baris pertama selalu ada di frame. NTH_VALUE dan LAST_VALUE butuh frame yang dibuka ke UNBOUNDED FOLLOWING biar lihat seluruh grup.
Contoh kasus: transaksi ke-2 tiap pelanggan toko_berkah
Pertanyaan dari tim marketing toko_berkah: berapa nilai belanja kedua tiap pelanggan? Ini kepake buat tau apakah belanja kedua lebih gede dari yang pertama, tanda pelanggan mulai percaya.
Data mentah pelanggan P-0087:
tanggal nilai
2026-02-03 45000
2026-02-11 120000
2026-03-02 88000
2026-04-15 210000
Query-nya pakai NTH_VALUE dengan frame penuh, terus bandingin sama FIRST_VALUE:
WITH banding AS (
SELECT
pelanggan_id,
FIRST_VALUE(nilai) OVER w AS belanja_pertama,
NTH_VALUE(nilai, 2) OVER w AS belanja_kedua
FROM transaksi
WINDOW w AS (
PARTITION BY pelanggan_id
ORDER BY tanggal
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
)
)
SELECT DISTINCT
pelanggan_id,
belanja_pertama,
belanja_kedua,
ROUND(100.0 * (belanja_kedua - belanja_pertama) / belanja_pertama, 1) AS naik_persen
FROM banding
WHERE belanja_kedua IS NOT NULL;
Dari 1.240 pelanggan yang belanja minimal dua kali, hasilnya: belanja kedua rata-rata 34 persen lebih gede dari yang pertama. Untuk P-0087, dari Rp 45.000 ke Rp 120.000, naik 167 persen.
Insight buat marketing: pelanggan yang balik lagi cenderung belanja lebih banyak. Jadi dorongan buat belanja kedua (misalnya voucher setelah transaksi pertama) sepadan sama nilainya.
Klausa WINDOW di query itu bikin definisi frame ditulis sekali, dipakai dua fungsi. Kalau kamu belum kenal CTE yang bungkus query ini, cek glossary CTE.
Kesalahan umum NTH_VALUE
1. Lupa frame. Ini nomor satu. Tanpa ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING, hasilnya NULL di baris-baris awal.
2. Ngira N mulai dari 0. NTH_VALUE mulai dari 1. NTH_VALUE(nilai, 1) sama aja kayak FIRST_VALUE.
3. Lupa PARTITION BY. Tanpa partisi, hitungan nyampur antar grup. Baris ke-2 diambil dari seluruh tabel, bukan per pelanggan.
4. Pakai di SQL Server. Fungsinya nggak ada di sana. Kamu harus tiru pakai ROW_NUMBER dan CASE.
5. Nganggap N lebih besar dari jumlah baris bakal error. Nggak error, cuma balikin NULL. NTH_VALUE(nilai, 5) di grup yang cuma 3 baris hasilnya NULL.
FAQ
NTH_VALUE ada di database apa aja?
NTH_VALUE ada di PostgreSQL sejak versi 9.4, MySQL 8.0 ke atas, Oracle, dan BigQuery. Yang perlu kamu catat: SQL Server dan SQLite nggak punya NTH_VALUE. Kalau kamu pakai dua itu, kamu harus tiru pakai kombinasi ROW_NUMBER dan CASE, atau pakai subquery. Cek dulu database kamu sebelum ngandelin fungsi ini di query produksi.
Kenapa NTH_VALUE ngasih hasil NULL terus?
Biasanya gara-gara frame default. Tanpa klausa frame, SQL cuma ngelihat dari baris pertama sampai baris sekarang. Jadi NTH_VALUE(nilai, 3) balikin NULL di baris 1 dan 2, karena baris ke-3 belum kelihatan. Buat lihat seluruh grup, tambahin ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING di dalam OVER. Setelah itu hasilnya konsisten di semua baris.
Apa beda NTH_VALUE dan ROW_NUMBER?
ROW_NUMBER ngasih nomor urut ke tiap baris, jadi hasilnya angka 1, 2, 3, dan seterusnya. NTH_VALUE ngambil nilai dari baris ke-N, jadi hasilnya isi kolom yang kamu tunjuk. Kalau kamu mau tau baris ke berapa, pakai ROW_NUMBER. Kalau kamu mau tau nilai apa yang ada di baris ke-N, pakai NTH_VALUE. Keduanya sama-sama window function.
Bisa nggak NTH_VALUE dipakai buat ambil nilai terakhir?
Bisa, tapi LAST_VALUE lebih pas buat itu. NTH_VALUE butuh kamu tau posisi angka ke berapa, sementara jumlah baris tiap grup bisa beda-beda. Kalau kamu mau nilai terakhir, pakai LAST_VALUE dengan frame ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING. Pakai NTH_VALUE kalau posisi yang kamu incar ada di tengah, misalnya transaksi ke-2 atau ke-3.
NTH_VALUE butuh ORDER BY nggak?
Butuh, hampir selalu. Tanpa ORDER BY di dalam OVER, urutan barisnya nggak pasti, jadi baris ke-N nggak punya arti yang jelas. ORDER BY yang nentuin mana baris pertama, kedua, dan seterusnya. Kalau kamu punya grup kayak per pelanggan, pasangin juga PARTITION BY biar hitungannya mulai ulang di tiap grup, bukan nyampur antar pelanggan.
Penutup
NTH_VALUE ngambil nilai baris ke-N dalam window. Kunci pakainya cuma satu: buka frame-nya ke UNBOUNDED FOLLOWING kalau posisi yang kamu incar ada di depan baris sekarang.
Latihan cepat: ambil tabel transaksi di kerjaanmu, hitung nilai belanja kedua tiap pelanggan, dan bandingin sama yang pertama. Pola naik atau turunnya sering bikin kaget.
Lanjut ke running total di SQL buat window function yang lain, atau dalami dulu glossary window function. Acuan resminya di dokumentasi window function PostgreSQL.
Mau praktek langsung? Mulai latihan SQL gratis
Latihan interaktif, langsung di browser.
Artikel terkait
Running Max dan Min dengan Window Function SQL
Lacak nilai tertinggi dan terendah berjalan di SQL pakai window function MAX dan MIN OVER. Ini sintaks, frame clause, dan contoh rekor omzet toko.
Analisa Afinitas Produk (Cross-Sell) dengan SQL
Produk apa yang sering dibeli bareng? Analisa afinitas produk pakai SQL self JOIN jawab itu. Ini cara hitung support, confidence, dan lift buat strategi cross-sell.
First Touch vs Last Touch Attribution di SQL
Channel mana yang dapat kredit konversi, yang pertama atau terakhir? Ini cara hitung first touch dan last touch attribution di SQL pakai window function.