Cheat Sheet SQL Analis: Semua Klausa dalam Satu Halaman
TL;DR
Cheat sheet SQL analis adalah rangkuman klausa dan fungsi yang paling sering dipakai buat analisis data harian. Urutan penulisannya SELECT, FROM, JOIN, WHERE, GROUP BY, HAVING, ORDER BY, LIMIT, tapi urutan eksekusinya beda: FROM dulu, SELECT hampir terakhir. Beda urutan itu yang jelasin kenapa alias di SELECT nggak bisa dipakai di WHERE.
Ini rangkuman SQL yang kepakai tiap hari buat kerjaan analis. Sekali baca, lalu simpan dan buka lagi pas butuh.
Hal yang paling sering bikin query pemula error bukan sintaks, tapi urutan. SQL ditulis dengan satu urutan, tapi dijalanin dengan urutan lain.
Gimana urutan klausa SQL yang bener?
Urutan penulisannya: SELECT, FROM, JOIN, WHERE, GROUP BY, HAVING, ORDER BY, LIMIT. Urutan eksekusinya beda: FROM dan JOIN dulu, lalu WHERE, GROUP BY, HAVING, baru SELECT, ORDER BY, dan LIMIT paling akhir. Beda urutan ini yang bikin alias dari SELECT nggak bisa dipanggil di WHERE.
| Urutan tulis | Urutan jalan | Fungsinya |
|---|---|---|
| 1. SELECT | 5 | Pilih kolom yang ditampilkan |
| 2. FROM | 1 | Ambil tabel sumber |
| 3. JOIN | 2 | Gabungin tabel lain |
| 4. WHERE | 3 | Saring baris sebelum digrupin |
| 5. GROUP BY | 4a | Kelompokin baris |
| 6. HAVING | 4b | Saring hasil grup |
| 7. ORDER BY | 6 | Urutkan hasil |
| 8. LIMIT | 7 | Potong jumlah baris |
Hafalin satu hal aja dari tabel ini: FROM duluan, SELECT belakangan.
Fungsi agregat apa yang wajib hafal?
Lima fungsi nutup hampir semua kebutuhan: COUNT buat ngitung baris, SUM buat total, AVG buat rata-rata, MIN dan MAX buat nilai terkecil dan terbesar. Semuanya ngabaikan NULL kecuali COUNT bintang, yang ngitung semua baris apa pun isinya.
| Fungsi | Hasil | Catatan |
|---|---|---|
COUNT(*) | Jumlah semua baris | NULL ikut kehitung |
COUNT(kolom) | Jumlah baris yang kolomnya terisi | NULL dilewati |
COUNT(DISTINCT kolom) | Jumlah nilai unik | Buat ngitung pelanggan unik |
SUM(kolom) | Total | Hasilnya NULL kalau semua baris NULL |
AVG(kolom) | Rata-rata | Penyebutnya cuma baris non NULL |
MIN / MAX | Nilai terkecil dan terbesar | Jalan juga buat teks dan tanggal |
Definisi lengkapnya ada di halaman aggregate function kalau kamu butuh penjelasan istilahnya.
SELECT
kota,
COUNT(*) AS jumlah_baris,
COUNT(DISTINCT pelanggan_id) AS pelanggan_unik,
SUM(nilai) AS total,
ROUND(AVG(nilai), 0) AS rata_rata
FROM transaksi
GROUP BY kota;
Kapan pakai JOIN yang mana?
Pilih dari sisi mana yang barisnya harus tetap utuh. INNER JOIN cuma nyisain baris yang cocok di kedua tabel. LEFT JOIN nahan semua baris tabel kiri. RIGHT JOIN kebalikannya. FULL OUTER JOIN nahan semuanya dari dua sisi.
| JOIN | Hasil | Kapan dipakai |
|---|---|---|
INNER JOIN | Cuma yang cocok | Transaksi yang produknya masih ada di master |
LEFT JOIN | Semua kiri + yang cocok | Semua pelanggan, walau belum pernah belanja |
RIGHT JOIN | Semua kanan + yang cocok | Jarang, biasanya ditulis ulang jadi LEFT |
FULL OUTER JOIN | Semua dari dua sisi | Nyocokin dua sumber data yang sama-sama nggak lengkap |
CROSS JOIN | Semua kombinasi | Bikin kerangka tanggal kali kota |
Jebakan paling sering: LEFT JOIN yang kondisinya ditaruh di WHERE. Begitu kamu nulis WHERE b.kolom = 'x' pada tabel kanan, LEFT JOIN kamu berubah jadi INNER JOIN diam-diam. Taruh kondisinya di klausa ON.
-- Salah: LEFT JOIN jadi INNER
SELECT p.nama, t.nilai
FROM pelanggan AS p
LEFT JOIN transaksi AS t ON t.pelanggan_id = p.id
WHERE t.status = 'selesai';
-- Benar
SELECT p.nama, t.nilai
FROM pelanggan AS p
LEFT JOIN transaksi AS t
ON t.pelanggan_id = p.id
AND t.status = 'selesai';
Window function mana yang paling sering dipakai?
Enam window function nutup mayoritas kebutuhan analis: ROW_NUMBER, RANK, DENSE_RANK, LAG, LEAD, dan SUM dengan OVER. Bedanya sama GROUP BY, window function ngitung agregat tanpa ngeciutin baris, jadi detail dan totalnya bisa muncul bareng.
| Fungsi | Dipakai buat |
|---|---|
ROW_NUMBER() | Nomor urut, ambil 1 baris terbaru per pelanggan |
RANK() | Peringkat, nilai sama dapat peringkat sama dan nomor berikutnya lompat |
DENSE_RANK() | Peringkat tanpa lompatan nomor |
LAG(kolom) | Nilai baris sebelumnya, buat hitung pertumbuhan |
LEAD(kolom) | Nilai baris berikutnya, buat hitung jarak antar order |
SUM(x) OVER (...) | Running total dan persentase kontribusi |
SELECT
bulan,
nilai,
LAG(nilai) OVER (ORDER BY bulan) AS nilai_bulan_lalu,
ROUND(
100.0 * (nilai - LAG(nilai) OVER (ORDER BY bulan))
/ NULLIF(LAG(nilai) OVER (ORDER BY bulan), 0),
1
) AS pertumbuhan_persen
FROM penjualan_bulanan;
Daftar lengkap beserta aturan frame-nya ada di dokumentasi window function PostgreSQL. Versi panjangnya juga aku bahas di panduan ROW_NUMBER dan RANK.
Fungsi tanggal, teks, dan NULL yang sering kepakai
| Kebutuhan | PostgreSQL | MySQL |
|---|---|---|
| Potong ke awal bulan | DATE_TRUNC('month', tgl) | DATE_FORMAT(tgl,'%Y-%m-01') |
| Ambil tahun | EXTRACT(YEAR FROM tgl) | YEAR(tgl) |
| Selisih hari | tgl_a - tgl_b | DATEDIFF(tgl_a, tgl_b) |
| Tanggal hari ini | CURRENT_DATE | CURDATE() |
| Gabung teks | a || b | CONCAT(a, b) |
| Ganti NULL | COALESCE(a, 0) | COALESCE(a, 0) |
| Hindari bagi nol | NULLIF(a, 0) | NULLIF(a, 0) |
Dua pola NULL yang paling sering nyelametin query:
-- Ganti NULL jadi 0 biar penjumlahan nggak bolong
COALESCE(diskon, 0)
-- Cegah error division by zero
ROUND(100.0 * berhasil / NULLIF(total, 0), 1)
Contoh kasus: satu query rekap toko_berkah
Query di kolom SQL artikel ini jalan di dataset toko_berkah punya ngulikdata, 41.892 baris transaksi setahun dari satu toko sembako di Bekasi.
Hasilnya 9 kategori produk. Tiga besarnya:
| Kategori | Total nilai | Kontribusi | Transaksi |
|---|---|---|---|
| Beras dan tepung | Rp 486.310.000 | 31,2% | 9.847 |
| Minyak dan bumbu | Rp 298.740.000 | 19,2% | 12.104 |
| Minuman kemasan | Rp 214.520.000 | 13,8% | 14.663 |
Yang menarik: minuman kemasan punya transaksi terbanyak tapi kontribusi nilainya paling kecil dari tiga itu. Rata-rata nilainya cuma Rp 14.630 per transaksi, sementara beras Rp 49.390.
Buat pemilik toko, angka itu ngasih arah jelas. Promo yang naikin frekuensi kunjungan nggak bakal ngangkat omzet sebanyak promo yang naikin ukuran keranjang beras. Cara ngukurnya ada di halaman metric.
Kesalahan umum yang bikin angka salah
- Kolom di SELECT nggak ada di GROUP BY. PostgreSQL bakal nolak, MySQL kadang diam-diam ngasih nilai acak dari grup itu.
- Kondisi tabel kanan ditaruh di WHERE pada LEFT JOIN. Barisnya kepotong tanpa peringatan.
- Bagi pakai bilangan bulat.
50 / 100hasilnya 0 di banyak database. Tulis50.0 / 100. - COUNT dipakai buat ngitung pelanggan. Tanpa DISTINCT, satu pelanggan yang belanja 12 kali kehitung 12 orang.
- Filter tanggal pakai BETWEEN pada kolom timestamp.
BETWEEN '2025-01-01' AND '2025-01-31'ngebuang transaksi tanggal 31 setelah jam 00.00. - Subquery bertingkat empat lapis. Pecah jadi CTE. Cara nyusunnya ada di panduan CTE SQL.
FAQ
Kenapa alias di SELECT nggak bisa dipakai di WHERE?
Gara-gara urutan eksekusi. WHERE dijalanin sebelum SELECT, jadi waktu WHERE bekerja, alias yang kamu bikin di SELECT belum ada. Solusinya dua: tulis ulang ekspresinya penuh di WHERE, atau bungkus query-nya jadi CTE lalu filter di query luar. Cara kedua lebih enak dibaca kalau ekspresinya panjang.
Bedanya COUNT(*) sama COUNT(nama_kolom) apa?
COUNT(*) ngitung semua baris, termasuk yang isinya NULL. COUNT(nama_kolom) cuma ngitung baris yang kolom itu ada isinya. Kalau kolom email kosong di 300 baris, COUNT(*) bisa bilang 1.000 sementara COUNT(email) bilang 700. Beda ini sering jadi sumber angka laporan yang nggak cocok antar tim.
Kapan pakai HAVING dan kapan pakai WHERE?
WHERE buat nyaring baris sebelum digrupin, HAVING buat nyaring hasil grup setelah agregat dihitung. Mau buang transaksi batal, pakai WHERE. Mau nyisain kategori yang totalnya di atas Rp 1 juta, pakai HAVING. Kalau kondisimu nggak nyentuh fungsi agregat, taruh di WHERE, hasilnya lebih cepat.
Window function beda apa sama GROUP BY?
GROUP BY ngeciutin banyak baris jadi satu baris per grup. Window function ngitung nilai agregat tapi baris aslinya tetap utuh. Jadi kamu bisa nampilin detail transaksi sekaligus total per kota di baris yang sama. Ini yang bikin window function enak buat running total, peringkat, dan persentase kontribusi.
Cheat sheet ini jalan di MySQL dan SQL Server juga?
Sebagian besar iya, soalnya klausa inti SQL itu standar. Yang beda biasanya fungsi tanggal dan limit baris. PostgreSQL pakai DATE_TRUNC dan LIMIT, MySQL pakai DATE_FORMAT dan LIMIT, SQL Server pakai DATEPART dan TOP. Cek dokumentasi database kamu buat dua bagian itu, sisanya bisa langsung dipakai.
Cara pakai cheat sheet ini
Dua tabel yang paling sering kamu buka lagi: urutan eksekusi klausa dan pilihan JOIN.
Sisanya bakal nempel sendiri setelah kamu nulis query yang sama beberapa kali.
Buka database kamu sekarang, tulis ulang query terakhir yang kamu pakai, lalu tambahin satu window function ke situ. Lima menit, dan kamu langsung tau bagian mana yang belum kebayang.
Mau praktek langsung? Mulai latihan SQL gratis
Latihan interaktif, langsung di browser.
Artikel terkait
Cara Membuat Pivot Dinamis di SQL (Panduan 2026)
Pivot dinamis di SQL ngubah baris jadi kolom tanpa kamu hardcode nama kolomnya. Ini cara bikinnya pakai CASE WHEN dan versi yang kolomnya ngikut data.
Menghitung YTD, QTD, dan MTD di SQL (Panduan 2026)
YTD, QTD, dan MTD ngukur total dari awal tahun, kuartal, atau bulan sampai hari ini. Ini cara ngitungnya di SQL pakai DATE_TRUNC, plus satu query gabungan.
Gap and Island Analysis di SQL
Gap and island analysis di SQL nyari deret data yang berturut-turut (island) dan celah yang bolong (gap). Cocok buat hitung streak login atau cari tanggal transaksi yang hilang.