Main Logo
  • Home
  • About
  • Kursus
    • Paket Kursus
    • Roadmap Profesi
    • Data & AI
      • Data Analyst
      • Data Scientist
      • AI Engineer
      • Data Engineer
      • Business Intelligence (BI) Specialist
    • Infrastruktur & Keamanan
      • Network Engineer
      • System Engineer
      • DevOps Engineer
      • Security Engineer
      • Cloud Engineer
    • Programming & Web Development
      • Web & App Developer
      • Web Developer
      • WordPress Developer
      • Mobile Developer
    • Spesialisasi
      • Blockchain Engineer
      • IOT Engineer
      • Digital Marketing Specialist
  • Elearning
  • Blog
  • Portfolio
Daftar
Main Logo
  • Home
  • About
  • Kursus
    • Paket Kursus
    • Roadmap Profesi
    • Data & AI
      • Data Analyst
      • Data Scientist
      • AI Engineer
      • Data Engineer
      • Business Intelligence (BI) Specialist
    • Infrastruktur & Keamanan
      • Network Engineer
      • System Engineer
      • DevOps Engineer
      • Security Engineer
      • Cloud Engineer
    • Programming & Web Development
      • Web & App Developer
      • Web Developer
      • WordPress Developer
      • Mobile Developer
    • Spesialisasi
      • Blockchain Engineer
      • IOT Engineer
      • Digital Marketing Specialist
  • Elearning
  • Blog
  • Portfolio

Kenapa Query SQL Kamu Ribet Banget Cuma untuk Cari “Top 3 per Kategori”? Kenalan dengan Window Function

  • September 16, 2026
  • oleh Sandya Gifta Ulimaz Sofiamagaski

Pernahkah kamu duduk di depan layar monitor sambil mengelus dada karena query SQL yang kamu tulis bentuknya makin mirip mi instan pilin-memilin, padahal tugas yang diminta atasan sangat sederhana: menampilkan 3 produk terlaris dari masing-masing kategori produk?

Jika kamu pernah berada di posisi itu—menulis self-join bertingkat-tingkat, menumpuk subquery yang membingungkan, hanya untuk memfilter peringkat—kamu tidak sendirian. Masalah “Top N per kelompok” adalah salah satu tembok besar yang paling sering membuat database developer, backend engineer, dan data analyst junior menggaruk kepala yang tidak gatal.

Good news-nya: SQL sebenarnya sudah punya fitur bawaan yang memang diciptakan khusus untuk menyelesaikan masalah ini secara bersih, elegan, dan jauh lebih cepat. Fitur sakti tersebut bernama Window Function.

Di artikel ini kita akan belajar cara mengubah query SQL tradisional yang rumit menjadi query Window Function yang bersih dan cepat, lengkap dengan praktik langsung menggunakan dataset transaksi yang bisa kamu coba sendiri di database kamu.


Skenario Nyata: Masalah “Top N per Kelompok”

Mari kita mulai dari skenario nyata yang sering kita temui di dunia kerja. Bayangkan kamu sedang mengelola database backend sebuah aplikasi e-commerce. Kamu memiliki tabel transaksi penjualan dan diminta oleh tim produk untuk menampilkan top 3 transaksi penjualan terbesar untuk setiap kategori barang.

Jika kamu hanya mengandalkan perintah dasar SQL yang diajarkan di kelas dasar—seperti GROUP BY dan ORDER BY—kamu akan langsung membentur tembok. Kenapa?

Sebab, fungsi utama GROUP BY adalah memadatkan (collapse) banyak baris menjadi satu baris rangkuman ringkas. Saat kamu mengelompokkan data berdasarkan kategori barang, kamu secara otomatis kehilangan akses ke baris detail transaksi individual di dalam kategori tersebut.

Cara Lama: Correlated Subquery

Sebelum fitur Window Function didukung secara luas di berbagai Sistem Manajemen Database (DBMS), berikut adalah salah satu bentuk query yang terpaksa ditulis oleh para developer menggunakan teknik correlated subquery:

SELECT p1.kategori, p1.nama_produk, p1.total_penjualan
FROM penjualan p1
WHERE (
    SELECT COUNT(*)
    FROM penjualan p2
    WHERE p2.kategori = p1.kategori 
      AND p2.total_penjualan > p1.total_penjualan
) < 3
ORDER BY p1.kategori, p1.total_penjualan DESC;

Jika kita bedah dari kacamata engineering dan efisiensi sistem, metode tradisional di atas menyimpan setidaknya tiga masalah besar:

  1. Performa yang sangat buruk (skalabilitas rendah). Query di atas menggunakan teknik correlated subquery. Artinya, untuk setiap satu baris data yang ada di tabel p1, mesin database harus mengeksekusi ulang seluruh subquery pada tabel p2. Jika tabelmu memiliki 100.000 baris transaksi, database akan melakukan komparasi berulang hingga ratusan ribu kali. Akibatnya, query menjadi sangat lambat dan membebani memori server hingga terjadi lonjakan penggunaan CPU.
  2. Keterbacaan kode yang buruk (poor readability). Bagi anggota tim lain yang baru pertama kali membaca kode ini saat proses code review, logika WHERE (SELECT COUNT(*)...) < 3 sama sekali tidak intuitif. Butuh waktu ekstra bagi siapa pun untuk mencerna apa maksud sebenarnya dari pembandingan jumlah baris tersebut.
  3. Penanganan nilai seri (tie handling) yang ringkih. Jika ada dua produk dalam satu kategori yang memiliki nilai penjualan identik, query tradisional di atas sering kali memberikan jumlah output yang salah, misalnya malah menampilkan 4 produk padahal batas syarat yang diminta hanya 3 produk.

GROUP BY vs Window Function

Sebelum masuk ke praktik, penting untuk benar-benar memahami perbedaan mendasar antara kedua konsep pengelompokan data ini.

Secara sederhana, Window Function adalah fitur dalam SQL yang memungkinkan kita melakukan kalkulasi agregasi atau pemeringkatan lintas sekumpulan baris tabel (a set of table rows), tanpa menghilangkan identitas dan detail dari baris aslinya.

Mari kita bandingkan perbedaannya secara langsung:

AspekGROUP BYWindow Function
Perlakuan barisMenggabungkan (collapse) baris-baris dataMempertahankan seluruh baris data
Hasil dari 10 baris inputMemadat menjadi 1 baris rangkumanTetap 10 baris, ditambah kolom hasil kalkulasi

Nama “window” sendiri berasal dari konsep “jendela” atau kumpulan baris (frame) tertentu yang ditentukan oleh sistem untuk dihitung pada saat baris data aktif sedang diproses.


Anatomi Window Function

Tidak perlu bingung saat menulis Window Function. Ada rumus baku yang bisa langsung kamu terapkan setiap kali membuat query pemeringkatan:

[FUNGSI_WINDOW()] OVER (PARTITION BY [kolom_kelompok] ORDER BY [kolom_patokan] DESC)

Contoh penerapannya di lapangan:

  • DENSE_RANK() OVER (PARTITION BY kategori ORDER BY total_penjualan DESC) → Menghasilkan nomor urut peringkat penjualan tanpa melompati angka jika ada nilai omzet yang seri.
  • ROW_NUMBER() OVER (PARTITION BY kategori ORDER BY tanggal_transaksi DESC) → Menghasilkan nomor baris sekuensial unik untuk setiap transaksi di tiap kategori.

Tiga Fungsi Pemeringkatan Utama

Untuk menyelesaikan kasus pemeringkatan seperti “Top N”, ada tiga fungsi pemeringkatan utama yang wajib kamu pahami bedanya:

  • ROW_NUMBER() — Memberikan nomor urut unik secara sekuensial (1, 2, 3, 4, dst.) untuk setiap baris data di dalam kelompoknya. Jika ada dua baris bernilai persis sama, ROW_NUMBER() tetap memberi urutan berbeda.
  • RANK() — Memberikan nilai peringkat yang sama jika ditemukan nilai data yang setara, namun melompati urutan nomor berikutnya (contoh: 1, 2, 2, 4).
  • DENSE_RANK() — Memberikan nilai peringkat yang sama untuk nilai data yang setara tanpa melompati nomor urut berikutnya (contoh: 1, 2, 2, 3). Ini adalah fungsi terbaik dan paling aman untuk kasus Top 3!

Praktik Langsung: Siapkan Dataset Kamu Sendiri

Supaya latihan ini terasa nyata, jangan langsung copy-paste data orang lain—buat dataset versi kamu sendiri. Bukalah query editor pilihanmu (DBeaver, pgAdmin, atau MySQL Workbench), lalu buat tabel dengan struktur berikut:

CREATE TABLE penjualan_elektronik (
    id INT PRIMARY KEY,
    nama_produk VARCHAR(100),
    kategori VARCHAR(50),
    total_penjualan BIGINT
);

Setelah tabel jadi, isi sendiri datanya dengan INSERT INTO. Supaya hasil “Top 3 per kategori” nanti benar-benar kelihatan bedanya, ikuti panduan berikut saat mengisi data:

  • Buat minimal 3 kategori berbeda (misalnya kategori produk yang biasa kamu jual/temui sehari-hari).
  • Isi minimal 4–5 baris produk untuk tiap kategori, supaya ada produk yang “tersisih” dari Top 3.
  • Sengaja buat dua baris dengan total_penjualan yang sama persis di salah satu kategori—ini penting supaya kamu bisa lihat sendiri bedanya RANK(), DENSE_RANK(), dan ROW_NUMBER() saat terjadi nilai seri (tie).

Contoh format INSERT yang bisa kamu sesuaikan:

INSERT INTO penjualan_elektronik (id, nama_produk, kategori, total_penjualan) VALUES
(1, 'Nama Produk 1', 'Kategori A', 0),
(2, 'Nama Produk 2', 'Kategori A', 0),
(3, 'Nama Produk 3', 'Kategori B', 0);
-- lanjutkan sendiri sampai semua kategori terisi

Setelah data kamu sendiri siap, lanjutkan ke query-query berikut menggunakan tabel penjualan_elektronik versi kamu.

Mau Kuasai Kenapa Query SQL Kamu Ribet Banget Cuma untuk Cari “Top 3 per Kategori”? Kenalan dengan Window Function Sampai Bisa Praktik Langsung?

Materi ini juga kami ajarkan langsung di kelas Edusoft Center, dibimbing mentor, sampai kamu bisa praktik nyata — bukan cuma baca teori.

Tanya Kursus via WhatsApp Lihat contoh project nyata dari siswa kami →

Menyelesaikan Kasus Top 3 dengan CTE + DENSE_RANK()

Sekarang mari kita selesaikan tantangan utama kita menggunakan kombinasi CTE (Common Table Expression) dan Window Function DENSE_RANK().

WITH PeringkatPenjualan AS (
    SELECT 
        kategori,
        nama_produk,
        total_penjualan,
        DENSE_RANK() OVER (
            PARTITION BY kategori 
            ORDER BY total_penjualan DESC
        ) AS rangking
    FROM penjualan_elektronik
)
SELECT 
    kategori,
    rangking,
    nama_produk,
    total_penjualan
FROM PeringkatPenjualan
WHERE rangking <= 3
ORDER BY kategori, rangking;

Query di atas bekerja dalam lima langkah intuitif di belakang layar:

  1. PARTITION BY mengelompokkan baris berdasarkan kategori.
  2. ORDER BY mengurutkan omzet penjualan secara menurun.
  3. DENSE_RANK menghitung angka peringkat tiap baris.
  4. CTE menyimpan tabel abstrak sementara bernama PeringkatPenjualan.
  5. WHERE rangking <= 3 menyaring hanya peringkat 1 sampai 3 dari tiap kelompok.

Membandingkan ROW_NUMBER, RANK, dan DENSE_RANK

Untuk membuktikan perbedaan nyata saat ada nilai penjualan yang persis sama (seperti Laptop Office Z dan Laptop Budget A yang sama-sama beromzet 90 juta), mari jalankan ketiga fungsi pemeringkatan tersebut sekaligus dalam satu query:

SELECT 
    kategori,
    nama_produk,
    total_penjualan,
    ROW_NUMBER() OVER (PARTITION BY kategori ORDER BY total_penjualan DESC) AS hasil_row_number,
    RANK() OVER (PARTITION BY kategori ORDER BY total_penjualan DESC) AS hasil_rank,
    DENSE_RANK() OVER (PARTITION BY kategori ORDER BY total_penjualan DESC) AS hasil_dense_rank
FROM penjualan_elektronik;
⚠️ Kesalahan yang Harus Dihindari
  • Langsung menggunakan klausa WHERE pada Window Function di query utama (Window Function harus dieksekusi di dalam CTE atau subquery terlebih dahulu).
  • Salah memilih antara RANK() dan DENSE_RANK() saat aturan bisnis membutuhkan urutan peringkat yang tidak boleh terputus atau melompat.
  • Lupa mencantumkan klausa ORDER BY di dalam OVER(), yang menyebabkan semua baris dalam kelompok mendapatkan nomor peringkat 1.
  • Tetap menggunakan correlated subquery lama untuk dataset berukuran jutaan baris di lingkungan produksi.

Lebih dari Sekadar Pemeringkatan

Hebatnya lagi, Window Function tidak terbatas pada pemeringkatan. Kamu bisa menggabungkannya dengan fungsi agregasi seperti SUM() untuk menghitung persentase kontribusi produk terhadap total kategori tanpa perlu melakukan query terpisah atau join tambahan.

SELECT 
    kategori,
    nama_produk,
    total_penjualan,
    SUM(total_penjualan) OVER (PARTITION BY kategori) AS total_penjualan_kategori,
    ROUND(
        (total_penjualan::NUMERIC / SUM(total_penjualan) OVER (PARTITION BY kategori)) * 100, 
        2
    ) AS persentase_kontribusi
FROM penjualan_elektronik
ORDER BY kategori, total_penjualan DESC;

Selain pemeringkatan dan agregasi dinamis, Window Function juga memiliki fungsi navigasi seperti LAG() dan LEAD() untuk mengintip nilai pada baris sebelum atau sesudahnya secara instan tanpa perlu melakukan self-join yang lambat.

SELECT 
    kategori,
    nama_produk,
    total_penjualan,
    LAG(total_penjualan, 1) OVER (PARTITION BY kategori ORDER BY total_penjualan DESC) AS penjualan_produk_diatasnya,
    total_penjualan - LAG(total_penjualan, 1) OVER (PARTITION BY kategori ORDER BY total_penjualan DESC) AS selisih_dengan_posisi_atas
FROM penjualan_elektronik;

Kenapa Ini Penting dari Sisi Performa

Jika kita melihat dari kacamata mesin database (query planner dan execution plan), penggunaan Window Function menawarkan keuntungan arsitektural yang sangat besar dibanding cara tradisional.

Pada metode subquery tradisional, mesin database terpaksa melakukan pembacaan tabel (full table scan atau index scan) secara berulang-ulang sebanyak jumlah baris data yang diproses. Jika terdapat 100.000 baris data, mesin akan membaca ulang tabel ratusan ribu kali, yang berujung pada tingginya angka I/O disk dan lonjakan penggunaan CPU server.

Sebaliknya, saat menggunakan Window Function, mesin database modern (seperti PostgreSQL, MySQL 8.0, Oracle, atau SQL Server) dapat mengoptimalkan eksekusi data hanya dengan satu kali pembacaan tabel (single pass scan) ditambah proses pengurutan lokal di memori (sort/hash step). Ini membuat proses eksekusi puluhan kali lebih cepat dan jauh lebih hemat sumber daya server.

Mungkin terdengar sederhana untuk hanya memikirkan query yang penting bisa jalan. Tapi di dunia kerja nyata, eksekusi query pada database berskala besar sering kali menjadi penentu utama responsivitas aplikasi backend maupun kecepatan loading dashboard analytics perusahaan.

Kalau kamu masih menggunakan correlated subquery tradisional, server database tempat aplikasi berjalan akan bekerja berulang kali untuk memproses baris yang sama. Dan ketika server harus bekerja terlalu keras, sistem cenderung lambat atau bahkan mengalami downtime saat diakses oleh banyak pengguna secara bersamaan.

Sebaliknya, ketika kamu menggunakan Window Function, database engine dapat melakukan optimasi eksekusi dalam waktu hitungan milidetik. Rekan tim backend, data engineer, dan atasan bisnis bisa langsung menikmati laporan data yang cepat, akurat, dan efisien.

Inilah yang membedakan seorang database developer yang biasa saja dengan yang profesional: bukan hanya soal membuat query yang bisa menghasilkan keluaran data, tapi membuat query yang efisien, berstruktur rapi, mudah dirawat, dan siap dipakai di tingkat produksi.


✅ Checklist Sebelum Finalisasi Query

Sebelum query SQL kamu dianggap selesai dan siap di-push ke repository atau diterapkan pada server produksi, coba jawab lima pertanyaan penting ini:

✅ Checklist Sebelum Finalisasi Query
  1. Apakah kamu sudah menggunakan CTE (WITH ... AS) agar struktur query mudah dibaca oleh tim lain?
  2. Apakah fungsi pemeringkatan yang dipilih (ROW_NUMBER, RANK, atau DENSE_RANK) sudah sesuai dengan aturan bisnis?
  3. Apakah klausa PARTITION BY dan ORDER BY di dalam OVER() sudah terpasang dengan benar dan tidak tertukar?
  4. Apakah filter batas peringkat sudah diletakkan pada outer query setelah pembuatan CTE?
  5. Apakah hasil akhir query sudah diuji pada kasus data yang memiliki nilai omzet kembar (tie)?

Penutup

Penulisan query SQL yang efisien bukan sekadar formalitas teknis. Ia adalah jembatan utama antara data mentah yang tersimpan di database dengan keputusan bisnis yang diambil oleh pemangku kepentingan perusahaan. Menguasai Window Function memberi kamu kemampuan menulis kode yang bersih, cepat, dan berstandar industri modern.

Mulai dari sekarang, setiap kali diminta membuat laporan Top N per kelompok atau pemeringkatan data, tinggalkan pola correlated subquery lama dan beralihlah menggunakan Window Function bersama CTE.

Satu perubahan kebiasaan kecil itu adalah investasi besar yang membuat seluruh hasil kerja analisis dan backend engineering kamu benar-benar berkualitas tinggi serta dihargai di lingkungan profesional.


Penulis: Sandya Gifta Ulimaz Sofiamagaski

Mau Kuasai Kenapa Query SQL Kamu Ribet Banget Cuma untuk Cari “Top 3 per Kategori”? Kenalan dengan Window Function Sampai Bisa Praktik Langsung?

Materi ini juga kami ajarkan langsung di kelas Edusoft Center, dibimbing mentor, sampai kamu bisa praktik nyata — bukan cuma baca teori.

Tanya Kursus via WhatsApp Lihat contoh project nyata dari siswa kami →

Tags: analisis databelajar sqlData AnalyticssqlSQL DatabaseSQL QuerySQL RankingSQL TutorialTop 3 per KategoriWindow Function
Previous Post
Next Post

Post comment

Cancel reply

Your email address will not be published. Required fields are marked *

Recent Posts

  • Mencari Produk yang Sering Dibeli Bersamaan Menggunakan SQL
  • Memindahkan Aplikasi PHP ke Cloud: Studi Kasus Deployment BloodConnect ke Hosting Publik
  • Kenapa Query SQL Kamu Ribet Banget Cuma untuk Cari “Top 3 per Kategori”? Kenalan dengan Window Function
  • Aplikasi Bisa Berjalan, Tapi Tidak Bisa Diakses? Cek dengan Wireshark
  • Tips Presentasi Final Project Data Analysis

Arsip

  • September 2026
  • August 2026
  • July 2026
  • June 2026
  • April 2026
  • March 2026
  • February 2026
  • January 2026
  • September 2025
  • August 2025
  • July 2025
  • March 2019
  • February 2019
  • January 2019
  • December 2018
  • November 2018
  • October 2018
  • September 2018
  • August 2018
  • July 2018
  • June 2018
  • May 2018
  • April 2018
  • March 2018
  • February 2018
  • January 2018
  • December 2017
  • November 2017
  • October 2017
  • September 2017
  • August 2017
  • July 2017
  • June 2017
  • May 2017
  • April 2017
  • March 2017
  • February 2017
  • January 2017
  • December 2016
  • November 2016
  • October 2016
  • September 2016
  • August 2016
  • July 2016
  • June 2016
  • May 2016
  • April 2016
  • March 2016
  • February 2016
  • January 2016
  • December 2015
  • November 2015
  • October 2015
  • September 2015
  • August 2015
  • July 2015
  • June 2015
  • May 2015
  • April 2015
  • March 2015
  • February 2015
  • January 2015
  • December 2014
  • November 2014
  • October 2014
  • September 2014
  • August 2014
  • July 2014
  • June 2014
  • May 2014
  • April 2014
  • March 2014
  • February 2014
  • January 2014
  • December 2013
  • November 2013
  • October 2013
  • September 2013
  • August 2013
  • July 2013
  • June 2013
  • May 2013
  • April 2013
  • March 2013
  • February 2013
  • January 2013
  • December 2012
  • November 2012
  • October 2012
  • September 2012
  • August 2012
  • July 2012
  • June 2012
  • May 2012
  • April 2012
  • December 2011
  • November 2011

Tags

apache web server dns server kursus android kursus database kursus dns dan web server kursus dns server kursus ethical hacking kursus hacking kursus jaringan kursus jaringan linux Kursus Komputer kursus komputer di solo kursus komputer di solo / surakarta kursus komputer di surakarta kursus linux Kursus Linux Forensics kursus linux networking kursus linux security kursus linux server kursus mikrotik kursus networking kursus network security kursus php Kursus PHP dan MySQL kursus php mysql kursus proxy kursus security kursus ubuntu kursus ubuntu server kursus web kursus web security kursus web server kursus wordpress kursus wordpress theme linux MySQL pelatihan komputer di solo PHP python security training komputer training komputer di solo tutorial php ubuntu wordpress

© Edusoft Center - Kursus Komputer di Solo | 2010 - 2026 | Privacy Policy | Site Map | Portfolio Magang | Butuh tim kami langsung yang mengerjakan? Lihat layanan implementasi →

All Right Reserved

WhatsApp us