50 Latihan Soal SQL Pemula + Kunci Jawaban
Blog/Tutorial SQL/50 Latihan Soal SQL Pemula + Kunci Jawaban

50 Latihan Soal SQL Pemula + Kunci Jawaban

BimaBima
·28 Juni 2026·13 menit baca

Penulis

Bima

Bima

Founder & Data Professional

Bagikan

TL;DR

Latihan soal SQL pemula paling efektif kalau pakai satu dataset yang sama dari awal sampai akhir, biar kamu hafal strukturnya dan bisa fokus ke logikanya. Halaman ini berisi 50 soal bertingkat, dari SELECT dasar sampai window function, semuanya pakai dataset toko_berkah berisi transaksi UMKM retail Indonesia. Kunci jawaban disediakan lengkap, tapi pola belajar yang paling berhasil adalah nyoba 10 menit dulu sebelum ngintip.

Cara tercepat jago SQL bukan nonton tutorial. Nulis query sendiri, salah, benerin, ulang.

Di bawah ini 50 soal bertingkat yang aku susun dari yang paling gampang sampai yang bikin mikir. Semua pakai satu dataset yang sama, biar kamu nggak buang waktu ngapalin struktur tabel baru tiap soal.

Kunci jawabannya ada semua. Tapi janji dulu: coba 10 menit sendiri sebelum ngintip.

Dataset yang dipakai: toko_berkah

Dataset toko_berkah berisi 18.400 transaksi dari 6 cabang UMKM retail sepanjang 2025. Ada dua tabel.

Tabel transaksi:

KolomTipeKeterangan
id_transaksiINTPrimary key
tanggalDATETanggal transaksi
cabangTEXTJakarta, Bekasi, Depok, Bandung, Surabaya, Semarang
id_pelangganINTForeign key ke tabel pelanggan
kategoriTEXTSembako, Snack, Minuman, Perawatan
jumlah_itemINTBanyak barang dibeli
total_hargaINTNilai transaksi dalam rupiah

Tabel pelanggan:

KolomTipeKeterangan
id_pelangganINTPrimary key
namaTEXTNama pelanggan
kotaTEXTKota domisili
tanggal_daftarDATEKapan pertama daftar member

Level 1: SELECT dan WHERE (soal 1-10)

  1. Tampilkan semua kolom dari tabel transaksi.
  2. Tampilkan cuma kolom tanggal, cabang, dan total_harga.
  3. Tampilkan semua transaksi dari cabang Bekasi.
  4. Tampilkan transaksi dengan total_harga di atas Rp500.000.
  5. Tampilkan transaksi kategori Sembako di cabang Depok.
  6. Tampilkan transaksi antara 1 Oktober dan 31 Desember 2025.
  7. Tampilkan transaksi yang jumlah_item-nya 5 atau lebih.
  8. Tampilkan transaksi dari cabang Jakarta ATAU Surabaya.
  9. Tampilkan transaksi yang total_harga-nya antara Rp100.000 dan Rp300.000.
  10. Tampilkan daftar kategori unik yang ada di tabel.

Kunci jawaban level 1

-- 1
SELECT * FROM transaksi;

-- 2
SELECT tanggal, cabang, total_harga FROM transaksi;

-- 3
SELECT * FROM transaksi WHERE cabang = 'Bekasi';

-- 4
SELECT * FROM transaksi WHERE total_harga > 500000;

-- 5
SELECT * FROM transaksi 
WHERE kategori = 'Sembako' AND cabang = 'Depok';

-- 6
SELECT * FROM transaksi 
WHERE tanggal BETWEEN '2025-10-01' AND '2025-12-31';

-- 7
SELECT * FROM transaksi WHERE jumlah_item >= 5;

-- 8
SELECT * FROM transaksi 
WHERE cabang IN ('Jakarta', 'Surabaya');

-- 9
SELECT * FROM transaksi 
WHERE total_harga BETWEEN 100000 AND 300000;

-- 10
SELECT DISTINCT kategori FROM transaksi;

Soal 8 bisa juga pakai OR. Tapi IN lebih rapi kalau daftarnya panjang.

Level 2: ORDER BY, LIMIT, dan fungsi teks (soal 11-20)

  1. Tampilkan 10 transaksi dengan nilai terbesar.
  2. Tampilkan 5 transaksi terlama (tanggal paling awal).
  3. Urutkan transaksi berdasarkan cabang, lalu total_harga dari besar ke kecil.
  4. Tampilkan 3 transaksi terbesar di cabang Bandung.
  5. Tampilkan nama pelanggan dalam huruf kapital semua.
  6. Tampilkan pelanggan yang namanya diawali huruf A.
  7. Tampilkan pelanggan yang namanya mengandung kata "Sari".
  8. Tampilkan panjang karakter nama tiap pelanggan.
  9. Tampilkan transaksi dengan harga per item, hasil pembagian total_harga dibagi jumlah_item.
  10. Tampilkan 10 transaksi dengan harga per item terendah.

Kunci jawaban level 2

-- 11
SELECT * FROM transaksi ORDER BY total_harga DESC LIMIT 10;

-- 12
SELECT * FROM transaksi ORDER BY tanggal ASC LIMIT 5;

-- 13
SELECT * FROM transaksi ORDER BY cabang ASC, total_harga DESC;

-- 14
SELECT * FROM transaksi 
WHERE cabang = 'Bandung' 
ORDER BY total_harga DESC LIMIT 3;

-- 15
SELECT UPPER(nama) AS nama_kapital FROM pelanggan;

-- 16
SELECT * FROM pelanggan WHERE nama LIKE 'A%';

-- 17
SELECT * FROM pelanggan WHERE nama LIKE '%Sari%';

-- 18
SELECT nama, LENGTH(nama) AS panjang_nama FROM pelanggan;

-- 19
SELECT 
    id_transaksi,
    total_harga,
    jumlah_item,
    ROUND(total_harga::numeric / NULLIF(jumlah_item, 0), 0) 
        AS harga_per_item
FROM transaksi;

-- 20
SELECT 
    id_transaksi,
    ROUND(total_harga::numeric / NULLIF(jumlah_item, 0), 0) 
        AS harga_per_item
FROM transaksi
ORDER BY harga_per_item ASC
LIMIT 10;

NULLIF(jumlah_item, 0) di soal 19 buat ngindarin error pembagian dengan nol. Kebiasaan kecil yang nyelametin banyak query.

Level 3: GROUP BY dan agregasi (soal 21-32)

  1. Hitung total transaksi di seluruh tabel.
  2. Hitung total omzet seluruh cabang.
  3. Hitung rata-rata nilai transaksi.
  4. Hitung omzet per cabang.
  5. Hitung jumlah transaksi per kategori.
  6. Hitung rata-rata nilai transaksi per cabang, urutkan dari besar ke kecil.
  7. Cari nilai transaksi tertinggi dan terendah per cabang.
  8. Hitung omzet per bulan.
  9. Hitung omzet per cabang per kategori.
  10. Tampilkan cabang yang omzetnya di atas Rp500 juta.
  11. Tampilkan kategori yang jumlah transaksinya lebih dari 3.000.
  12. Hitung berapa pelanggan unik yang belanja di tiap cabang.

Kunci jawaban level 3

-- 21
SELECT COUNT(*) AS jumlah_transaksi FROM transaksi;

-- 22
SELECT SUM(total_harga) AS total_omzet FROM transaksi;

-- 23
SELECT ROUND(AVG(total_harga), 0) AS rata_rata FROM transaksi;

-- 24
SELECT cabang, SUM(total_harga) AS omzet
FROM transaksi
GROUP BY cabang;

-- 25
SELECT kategori, COUNT(*) AS jumlah
FROM transaksi
GROUP BY kategori;

-- 26
SELECT cabang, ROUND(AVG(total_harga), 0) AS rata_rata
FROM transaksi
GROUP BY cabang
ORDER BY rata_rata DESC;

-- 27
SELECT 
    cabang,
    MAX(total_harga) AS tertinggi,
    MIN(total_harga) AS terendah
FROM transaksi
GROUP BY cabang;

-- 28
SELECT 
    EXTRACT(MONTH FROM tanggal) AS bulan,
    SUM(total_harga) AS omzet
FROM transaksi
GROUP BY 1
ORDER BY 1;

-- 29
SELECT cabang, kategori, SUM(total_harga) AS omzet
FROM transaksi
GROUP BY cabang, kategori
ORDER BY cabang, omzet DESC;

-- 30
SELECT cabang, SUM(total_harga) AS omzet
FROM transaksi
GROUP BY cabang
HAVING SUM(total_harga) > 500000000
ORDER BY omzet DESC;

-- 31
SELECT kategori, COUNT(*) AS jumlah
FROM transaksi
GROUP BY kategori
HAVING COUNT(*) > 3000;

-- 32
SELECT cabang, COUNT(DISTINCT id_pelanggan) AS pelanggan_unik
FROM transaksi
GROUP BY cabang;

Soal 30 dan 31 nguji hal yang sama: WHERE nyaring sebelum dikelompokin, HAVING nyaring sesudah. Ini yang paling sering ketuker.

Level 4: JOIN (soal 33-42)

  1. Tampilkan transaksi lengkap dengan nama pelanggannya.
  2. Tampilkan transaksi dengan nama dan kota pelanggan.
  3. Tampilkan semua pelanggan beserta transaksinya, termasuk yang belum pernah belanja.
  4. Cari pelanggan yang belum pernah transaksi sama sekali.
  5. Hitung total belanja per pelanggan, tampilkan namanya.
  6. Cari 10 pelanggan dengan total belanja terbesar.
  7. Hitung omzet per kota pelanggan.
  8. Cari pelanggan yang belanja di lebih dari satu cabang.
  9. Hitung omzet dari pelanggan yang daftar di 2025 aja.
  10. Bandingkan omzet pelanggan lama (daftar sebelum 2025) vs pelanggan baru.

Kunci jawaban level 4

-- 33
SELECT t.*, p.nama
FROM transaksi t
INNER JOIN pelanggan p ON t.id_pelanggan = p.id_pelanggan;

-- 34
SELECT t.id_transaksi, t.tanggal, t.total_harga, p.nama, p.kota
FROM transaksi t
INNER JOIN pelanggan p ON t.id_pelanggan = p.id_pelanggan;

-- 35
SELECT p.nama, t.id_transaksi, t.total_harga
FROM pelanggan p
LEFT JOIN transaksi t ON p.id_pelanggan = t.id_pelanggan;

-- 36
SELECT p.id_pelanggan, p.nama
FROM pelanggan p
LEFT JOIN transaksi t ON p.id_pelanggan = t.id_pelanggan
WHERE t.id_transaksi IS NULL;

-- 37
SELECT p.nama, SUM(t.total_harga) AS total_belanja
FROM pelanggan p
INNER JOIN transaksi t ON p.id_pelanggan = t.id_pelanggan
GROUP BY p.nama;

-- 38
SELECT p.nama, SUM(t.total_harga) AS total_belanja
FROM pelanggan p
INNER JOIN transaksi t ON p.id_pelanggan = t.id_pelanggan
GROUP BY p.nama
ORDER BY total_belanja DESC
LIMIT 10;

-- 39
SELECT p.kota, SUM(t.total_harga) AS omzet
FROM pelanggan p
INNER JOIN transaksi t ON p.id_pelanggan = t.id_pelanggan
GROUP BY p.kota
ORDER BY omzet DESC;

-- 40
SELECT p.nama, COUNT(DISTINCT t.cabang) AS jumlah_cabang
FROM pelanggan p
INNER JOIN transaksi t ON p.id_pelanggan = t.id_pelanggan
GROUP BY p.nama
HAVING COUNT(DISTINCT t.cabang) > 1;

-- 41
SELECT SUM(t.total_harga) AS omzet_pelanggan_baru
FROM pelanggan p
INNER JOIN transaksi t ON p.id_pelanggan = t.id_pelanggan
WHERE p.tanggal_daftar >= '2025-01-01';

-- 42
SELECT 
    CASE 
        WHEN p.tanggal_daftar < '2025-01-01' THEN 'Lama'
        ELSE 'Baru'
    END AS tipe_pelanggan,
    COUNT(DISTINCT p.id_pelanggan) AS jumlah_orang,
    SUM(t.total_harga) AS omzet
FROM pelanggan p
INNER JOIN transaksi t ON p.id_pelanggan = t.id_pelanggan
GROUP BY 1;

Soal 36 itu pola klasik: LEFT JOIN plus IS NULL buat nyari yang nggak punya pasangan. Sering keluar di interview.

Level 5: Subquery, CTE, dan window function (soal 43-50)

  1. Cari transaksi yang nilainya di atas rata-rata seluruh transaksi.
  2. Cari transaksi yang nilainya di atas rata-rata cabangnya sendiri.
  3. Pakai CTE buat hitung omzet per cabang, lalu tampilkan yang di atas rata-rata omzet semua cabang.
  4. Beri ranking transaksi terbesar di tiap cabang.
  5. Tampilkan 3 transaksi terbesar per cabang.
  6. Hitung omzet kumulatif per bulan (running total).
  7. Bandingkan omzet tiap bulan dengan bulan sebelumnya.
  8. Hitung persentase kontribusi tiap cabang terhadap total omzet.

Kunci jawaban level 5

-- 43
SELECT * FROM transaksi
WHERE total_harga > (SELECT AVG(total_harga) FROM transaksi);

-- 44
SELECT t.*
FROM transaksi t
WHERE t.total_harga > (
    SELECT AVG(total_harga) 
    FROM transaksi 
    WHERE cabang = t.cabang
);

-- 45
WITH omzet_cabang AS (
    SELECT cabang, SUM(total_harga) AS omzet
    FROM transaksi
    GROUP BY cabang
)
SELECT *
FROM omzet_cabang
WHERE omzet > (SELECT AVG(omzet) FROM omzet_cabang);

-- 46
SELECT 
    cabang,
    id_transaksi,
    total_harga,
    RANK() OVER (
        PARTITION BY cabang 
        ORDER BY total_harga DESC
    ) AS peringkat
FROM transaksi;

-- 47
WITH ranked AS (
    SELECT 
        cabang,
        id_transaksi,
        total_harga,
        ROW_NUMBER() OVER (
            PARTITION BY cabang 
            ORDER BY total_harga DESC
        ) AS rn
    FROM transaksi
)
SELECT cabang, id_transaksi, total_harga
FROM ranked
WHERE rn <= 3
ORDER BY cabang, total_harga DESC;

-- 48
WITH omzet_bulanan AS (
    SELECT 
        EXTRACT(MONTH FROM tanggal) AS bulan,
        SUM(total_harga) AS omzet
    FROM transaksi
    GROUP BY 1
)
SELECT 
    bulan,
    omzet,
    SUM(omzet) OVER (ORDER BY bulan) AS omzet_kumulatif
FROM omzet_bulanan
ORDER BY bulan;

-- 49
WITH omzet_bulanan AS (
    SELECT 
        EXTRACT(MONTH FROM tanggal) AS bulan,
        SUM(total_harga) AS omzet
    FROM transaksi
    GROUP BY 1
)
SELECT 
    bulan,
    omzet,
    LAG(omzet) OVER (ORDER BY bulan) AS omzet_bulan_lalu,
    omzet - LAG(omzet) OVER (ORDER BY bulan) AS selisih
FROM omzet_bulanan
ORDER BY bulan;

-- 50
SELECT 
    cabang,
    SUM(total_harga) AS omzet,
    ROUND(
        100.0 * SUM(total_harga) 
        / SUM(SUM(total_harga)) OVER (), 
        1
    ) AS persen_kontribusi
FROM transaksi
GROUP BY cabang
ORDER BY omzet DESC;

Soal 50 kelihatan aneh dengan SUM(SUM(...)) OVER (). Yang di dalam ngitung per cabang, yang di luar ngitung total semuanya. Ini trik yang kepake terus di kerjaan.

Contoh kasus: apa yang ketemu dari soal 50

Waktu aku jalanin soal 50 di dataset toko_berkah, hasilnya bikin berhenti sebentar.

CabangOmzetKontribusi
JakartaRp1,42 miliar28,4%
SurabayaRp1,08 miliar21,6%
BandungRp894 juta17,9%
SemarangRp731 juta14,6%
DepokRp512 juta10,2%
BekasiRp366 juta7,3%

Dua cabang teratas nyumbang separuh omzet. Bekasi cuma 7,3%, padahal jumlah transaksinya nggak jauh beda dari Depok.

Artinya masalah Bekasi ada di nilai per transaksi, bukan di jumlah pembeli. Satu query, satu temuan.

Kesalahan umum waktu ngerjain latihan SQL

Langsung ngintip kunci jawaban. Otak kamu belajar dari momen macet, bukan dari baca jawaban benar. Kasih 10 menit buat tiap soal.

Ketuker WHERE dan HAVING. WHERE nyaring baris sebelum dikelompokin. HAVING nyaring hasil kelompok. Kalau kamu nulis WHERE SUM(...) > 100, itu bakal error.

Lupa GROUP BY semua kolom non-agregasi. Kalau kamu SELECT cabang dan kategori tapi cuma GROUP BY cabang, hasilnya error di kebanyakan database.

Ngerjain 50 soal dalam sehari. Nggak bakal nempel. Pecah jadi 2 minggu, 5 soal per hari.

Nggak cek hasilnya masuk akal. Query yang jalan bukan berarti query yang benar. Selalu cek jumlah barisnya wajar.

Kalau kamu masih goyang di dasar, balik dulu ke halaman GROUP BY dan JOIN.

FAQ

Berapa lama waktu yang dibutuhkan buat ngerjain 50 soal ini?

Kalau kamu benar-benar pemula, sekitar 10-15 jam total, dan sebaiknya dipecah jadi 2 minggu. Level 1 sampai 3 biasanya lancar dalam 3-4 jam. Level 4 dan 5 yang makan waktu. Ngerjain 5 soal sampai paham betul lebih berguna dari nyontek 50 jawaban dalam sehari.

Apakah query di soal ini jalan di MySQL dan PostgreSQL?

Mayoritas jalan di dua-duanya. Yang beda cuma beberapa fungsi tanggal dan casting angka. Kalau kamu pakai MySQL lama, ganti EXTRACT(MONTH FROM tanggal) jadi MONTH(tanggal). Referensi lengkapnya ada di dokumentasi resmi PostgreSQL.

Harus install database dulu buat latihan SQL?

Nggak harus. Kamu bisa langsung praktek di editor SQL online yang jalan di browser. Kalau kamu mau setup sendiri, SQLite paling ringan dan cukup buat semua soal di halaman ini.

Urutan belajar SQL yang paling efektif buat pemula gimana?

SELECT dan WHERE dulu sampai lancar, lalu ORDER BY dan LIMIT, baru GROUP BY. Setelah itu JOIN, lalu subquery dan CTE, terakhir window function. Banyak orang lompat ke JOIN terlalu cepat lalu bingung, padahal masalahnya karena WHERE-nya belum kuat.

Apakah latihan soal SQL cukup buat lolos interview data analyst?

Cukup buat lolos tes teknisnya, tapi belum cukup buat lolos keseluruhan. Interviewer juga nanya kenapa kamu pilih pendekatan tertentu dan gimana kamu jelasin hasilnya ke orang non-teknis. Latih dua-duanya.

Penutup

Dua hal yang mau aku tinggalin. Kerjain 5 soal per hari, bukan 50 sekaligus. Dan cek hasilnya masuk akal, jangan cuma seneng karena querynya nggak error.

Mau langsung ngetik querynya tanpa install apa-apa? Buka NgulikSQL, editornya jalan di browser.

Baca juga: prospek kerja data analyst 2026 kalau kamu latihan SQL buat pindah karir.

Coba Langsung

Mau praktek langsung? Mulai latihan SQL gratis

Latihan interaktif, langsung di browser.

Buka NgulikSQL →
Bagikan:
Bima
Ditulis oleh

Bima

Founder & Data Professional

Founder Ngulik Data. Passionate about making data analysis accessible for everyone.

Artikel Terkait

7 SQL Client Gratis Terbaik buat Analis Data (2026)
Tutorial SQL
10 Juli 2026•9 menit baca

7 SQL Client Gratis Terbaik buat Analis Data (2026)

Nggak perlu bayar buat nulis query. Ini 7 SQL client gratis yang beneran dipakai analis, plus kelebihan dan kekurangannya masing-masing.

BimaBima
SQL Style Guide: Cara Nulis Query yang Enak Dibaca Tim
Tutorial SQL
7 Juli 2026•9 menit baca

SQL Style Guide: Cara Nulis Query yang Enak Dibaca Tim

Sepuluh aturan SQL style guide yang bikin query kamu kebaca sama tim — dan sama kamu sendiri 6 bulan lagi. Lengkap dengan contoh sebelum-sesudah.

BimaBima
Take-Home Test SQL Data Analyst: Contoh Soal + Cara Ngerjainnya
Tutorial SQL
4 Juli 2026•11 menit baca

Take-Home Test SQL Data Analyst: Contoh Soal + Cara Ngerjainnya

Contoh soal take-home test SQL yang beneran dipakai perusahaan, dikerjain step by step — dari baca soal, nulis query, sampai nyusun insight yang bikin recruiter nengok.

BimaBima
Kembali ke Blog
Ngulik Data logoNgulik Data

Platform edukasi data lengkap untuk professionals Indonesia. Belajar SQL, Data Analysis, dan lebih banyak lagi dengan praktek langsung dan feedback real-time.

Copyright © 2026 - All rights reserved

LINKS
SupportPricingDatasetBlogAffiliates
LEGAL
Terms of servicesPrivacy policy
Ngulik Data
DatasetLeaderboardBlogStore