Soal Interview SQL Bertema Produk plus Kerangka Jawabannya
Blog/Tutorial SQL/Soal Interview SQL Bertema Produk plus Kerangka Jawabannya

Soal Interview SQL Bertema Produk plus Kerangka Jawabannya

BimaBima
·12 September 2025·12 menit baca

Penulis

Bima

Bima

Founder & Data Professional

Bagikan

TL;DR

Soal interview SQL bertema produk nguji dua hal sekaligus: kemampuan nulis query dan pemahaman metrik produk kayak retensi, funnel, dan adopsi fitur. Pewawancara biasanya lebih peduli sama definisi metrik yang kamu pilih daripada kerapian sintaksnya. Delapan soal di artikel ini mencakup pola yang paling sering muncul di wawancara data analyst startup.

Soal interview SQL bertema produk nguji dua hal sekaligus: kemampuan nulis query dan pemahaman metrik produk.

Yang bikin kandidat gagal biasanya bukan sintaks. Mereka nulis query yang jalan, tapi ngukur hal yang salah.

Delapan soal di bawah pakai skema yang sama, jadi kamu bisa latihan berurutan. Tiap soal ada query jawaban, jebakannya, dan satu kalimat penutup yang bikin nilaimu naik.

Skema tabel yang dipakai

Semua soal pakai database aplikasi pesan antar makanan Warungku. Empat tabel, cukup buat hampir semua pertanyaan produk.

users      (user_id, signup_date, kota, sumber_akuisisi)
events     (event_id, user_id, event_name, event_time)
orders     (order_id, user_id, order_time, gmv, status)
eksperimen (user_id, grup, assigned_at)

Nilai event_name yang tersedia: buka_app, lihat_menu, masuk_keranjang, checkout, bayar_sukses, pakai_dompet.

Semua query di bawah pakai sintaks PostgreSQL.

Soal 1: Berapa DAU dan stickiness aplikasi bulan ini?

Stickiness adalah rata-rata DAU dibagi MAU. Angka ini ngasih tau berapa hari dalam sebulan seorang pengguna rata-rata buka aplikasi.

WITH dau AS (
  SELECT DATE_TRUNC('day', event_time)::date AS tanggal,
         COUNT(DISTINCT user_id) AS jml
  FROM events
  WHERE event_time >= CURRENT_DATE - INTERVAL '30 days'
  GROUP BY 1
),
mau AS (
  SELECT COUNT(DISTINCT user_id) AS jml
  FROM events
  WHERE event_time >= CURRENT_DATE - INTERVAL '30 days'
)
SELECT ROUND(AVG(dau.jml) / MAX(mau.jml), 3) AS stickiness
FROM dau CROSS JOIN mau;

Jebakannya: ngitung MAU dengan njumlahin DAU harian. Pengguna yang buka aplikasi 10 hari bakal kehitung 10 kali. MAU harus pakai COUNT DISTINCT di seluruh periode.

Kalimat penutup: "Stickiness 0,27 artinya rata-rata pengguna aktif buka aplikasi sekitar 8 hari dalam sebulan. Buat aplikasi makanan itu wajar, buat aplikasi chat itu sinyal bahaya."

Soal 2: Berapa retensi hari ke-7 pengguna baru Agustus?

Ini soal paling sering keluar. Pewawancara mau lihat kamu ngerti konsep kohor.

WITH kohor AS (
  SELECT user_id, signup_date::date AS tgl_daftar
  FROM users
  WHERE signup_date >= DATE '2025-08-01'
    AND signup_date <  DATE '2025-09-01'
),
aktif_d7 AS (
  SELECT DISTINCT k.user_id
  FROM kohor k
  JOIN events e ON e.user_id = k.user_id
  WHERE e.event_time::date = k.tgl_daftar + 7
)
SELECT
  COUNT(DISTINCT k.user_id) AS pengguna_baru,
  COUNT(DISTINCT a.user_id) AS aktif_hari_ke7,
  ROUND(100.0 * COUNT(DISTINCT a.user_id)
              / COUNT(DISTINCT k.user_id), 1) AS retensi_d7_persen
FROM kohor k
LEFT JOIN aktif_d7 a ON a.user_id = k.user_id;

Jebakannya: pakai tanggal absolut. Kalau kamu tulis event_time = DATE '2025-08-08', kamu cuma ngukur orang yang daftar tanggal 1. Hari ke-7 dihitung dari tanggal daftar masing-masing pengguna.

Yang bikin nilai naik: sebut bedanya retensi harian persis dan retensi rentang. Query di atas ngukur aktif tepat di hari ke-7. Banyak perusahaan pakai definisi "aktif di hari 7 sampai 13" karena angkanya lebih stabil. Tanya dulu definisi mana yang mereka pakai.

Kalau kamu belum akrab sama cara baca tabel kohor, mulai dari cohort analysis.

Soal 3: Di tahap mana pengguna paling banyak berhenti?

SELECT
  COUNT(DISTINCT user_id) FILTER (WHERE event_name = 'buka_app')       AS buka_app,
  COUNT(DISTINCT user_id) FILTER (WHERE event_name = 'lihat_menu')     AS lihat_menu,
  COUNT(DISTINCT user_id) FILTER (WHERE event_name = 'masuk_keranjang') AS keranjang,
  COUNT(DISTINCT user_id) FILTER (WHERE event_name = 'checkout')       AS checkout,
  COUNT(DISTINCT user_id) FILTER (WHERE event_name = 'bayar_sukses')   AS bayar_sukses
FROM events
WHERE event_time >= DATE '2025-09-01'
  AND event_time <  DATE '2025-10-01';

Klausa FILTER di PostgreSQL bikin query funnel jauh lebih pendek dari tumpukan CASE WHEN. Detailnya ada di dokumentasi fungsi agregat PostgreSQL.

Jebakannya: query ini nggak mastiin urutan. Pengguna yang checkout tanpa pernah lihat menu tetap kehitung. Buat funnel ketat, kamu perlu bandingin timestamp antar tahap per pengguna.

Kalimat penutup: "Angka ini funnel longgar. Kalau tim produk butuh urutan ketat, aku bakal pakai window function buat mastiin tiap event terjadi setelah event sebelumnya."

Soal 4: Berapa persen pengguna aktif yang nyoba fitur dompet minggu pertama?

WITH aktif AS (
  SELECT DISTINCT user_id FROM events
  WHERE event_time >= DATE '2025-09-01'
    AND event_time <  DATE '2025-09-08'
),
pemakai AS (
  SELECT DISTINCT user_id FROM events
  WHERE event_name = 'pakai_dompet'
    AND event_time >= DATE '2025-09-01'
    AND event_time <  DATE '2025-09-08'
)
SELECT
  (SELECT COUNT(*) FROM aktif)   AS pengguna_aktif,
  (SELECT COUNT(*) FROM pemakai) AS pemakai_fitur,
  ROUND(100.0 * (SELECT COUNT(*) FROM pemakai)
              / (SELECT COUNT(*) FROM aktif), 1) AS adopsi_persen;

Jebakannya: milih penyebut yang salah. Kalau kamu bagi sama total pengguna terdaftar, angkanya kecil banget dan nggak berarti. Adopsi fitur diukur dari pengguna yang beneran buka aplikasi di periode itu.

Yang bikin nilai naik: tanyain balik apakah fitur dompet ada di semua versi aplikasi. Kalau cuma tersedia di Android, penyebutnya harus dibatasi ke pengguna Android.

Soal 5: Berapa median waktu dari daftar sampai order pertama?

WITH pertama AS (
  SELECT u.user_id,
         u.signup_date,
         MIN(o.order_time) AS order_pertama
  FROM users u
  JOIN orders o ON o.user_id = u.user_id
  WHERE o.status = 'sukses'
  GROUP BY u.user_id, u.signup_date
)
SELECT
  ROUND(PERCENTILE_CONT(0.5) WITHIN GROUP (
    ORDER BY EXTRACT(EPOCH FROM (order_pertama - signup_date)) / 3600
  )::numeric, 1) AS median_jam
FROM pertama;

Jebakannya: pakai AVG. Beberapa pengguna baru order setelah 8 bulan, dan mereka narik rata-rata jauh ke atas. Median lebih jujur buat data waktu yang miring, dan alasannya sama kayak kenapa kamu hati-hati sama outlier.

Kalimat penutup: "Angka ini cuma buat pengguna yang akhirnya order. Kalau tim mau tau kesehatan onboarding, aku juga bakal laporin berapa persen pengguna yang nggak pernah order sama sekali."

Soal 6: Kota mana yang GMV per penggunanya paling tinggi?

SELECT
  u.kota,
  COUNT(DISTINCT u.user_id) AS jml_pengguna,
  SUM(o.gmv) AS total_gmv,
  ROUND(SUM(o.gmv) / COUNT(DISTINCT u.user_id)) AS gmv_per_pengguna
FROM users u
JOIN orders o ON o.user_id = u.user_id
WHERE o.status = 'sukses'
  AND o.order_time >= DATE '2025-09-01'
GROUP BY u.kota
HAVING COUNT(DISTINCT u.user_id) >= 50
ORDER BY gmv_per_pengguna DESC
LIMIT 5;

Jebakannya: lupa HAVING. Kota dengan 3 pengguna yang kebetulan satu di antaranya pesan katering kantor bakal nangkring di puncak. Ambang minimal jumlah pengguna wajib ada.

Yang bikin nilai naik: sebutin bahwa GMV per pengguna bukan KPI yang bisa berdiri sendiri. Kota dengan GMV per pengguna tinggi tapi jumlah pengguna kecil punya arti bisnis yang beda dari kota besar dengan angka sedang.

Soal 7: Berapa pengguna yang churn dalam 30 hari terakhir?

SELECT COUNT(*) AS pengguna_churn
FROM (
  SELECT user_id, MAX(order_time) AS order_terakhir
  FROM orders
  WHERE status = 'sukses'
  GROUP BY user_id
) t
WHERE order_terakhir < CURRENT_DATE - INTERVAL '30 days';

Jebakannya: nulis query sebelum nanya definisi churn. Di aplikasi makanan, 30 hari tanpa order itu wajar buat sebagian orang. Di aplikasi langganan, 30 hari itu udah pasti hilang.

Kalimat penutup: "Aku pakai 30 hari sebagai batas. Kalau tim punya definisi lain, angkanya tinggal diganti di satu tempat. Yang lebih berguna sebenernya laporan churn per kohor, biar kelihatan pengguna angkatan mana yang paling cepat pergi."

Soal 8: Grup mana yang menang di eksperimen checkout baru?

SELECT
  x.grup,
  COUNT(DISTINCT x.user_id) AS jml_pengguna,
  COUNT(DISTINCT o.user_id) AS jml_konversi,
  ROUND(100.0 * COUNT(DISTINCT o.user_id)
              / COUNT(DISTINCT x.user_id), 2) AS konversi_persen
FROM eksperimen x
LEFT JOIN orders o
       ON o.user_id = x.user_id
      AND o.status = 'sukses'
      AND o.order_time >= x.assigned_at
GROUP BY x.grup;

Jebakannya: pakai INNER JOIN. Pengguna yang nggak pernah order bakal hilang dari penyebut, dan konversi kedua grup jadi 100%.

Jebakan kedua: nggak ngasih syarat order_time >= assigned_at. Order yang terjadi sebelum pengguna masuk eksperimen nggak boleh dihitung.

Yang bikin nilai naik: bilang bahwa selisih persentase doang belum cukup buat nyimpulin pemenang. Kamu butuh uji signifikansi dan ukuran sampel yang memadai, dan itu bagian standar dari A/B testing.

Pola yang paling sering diuji

PolaMuncul di soalFungsi kunci
Hitung pengguna unik1, 3, 4COUNT DISTINCT
Kohor berbasis tanggal daftar2Tanggal relatif per pengguna
Agregat bersyarat3FILTER atau CASE WHEN
Kejadian pertama per pengguna5MIN atau ROW_NUMBER
Rasio dengan ambang minimal6HAVING
Pengguna tanpa aktivitas7, 8LEFT JOIN

Kalau kamu kuasai enam pola itu, sebagian besar soal wawancara SQL produk bisa kamu kerjain. Sisanya cuma variasi konteks.

Kesalahan umum di wawancara SQL produk

  1. Langsung nulis query. Habiskan 30 detik pertama buat nyamain definisi metriknya. Ini yang paling nentuin nilai.
  2. Diam sambil ngetik. Ucapkan rencananya: "aku bikin CTE kohor dulu, terus join ke events". Pewawancara nggak bisa baca pikiranmu.
  3. Ngejar query paling ringkas. Query pendek yang nggak kebaca lebih jelek dari CTE bertingkat yang jelas.
  4. Lupa status transaksi. Tabel orders punya baris gagal dan batal. Filter status = 'sukses' hampir selalu perlu.
  5. Nggak nyebut keterbatasan. Satu kalimat soal batasan angkamu bikin kamu kelihatan kayak analyst, bukan penulis query.

FAQ

Boleh nanya struktur tabel dulu waktu dikasih soal SQL?

Boleh, dan justru itu yang diharapkan. Tanya nama kolom kunci, tipe datanya, dan apakah ada baris duplikat. Pewawancara sering sengaja ngasih soal setengah jelas buat lihat apakah kamu asal nulis query atau mastiin asumsinya dulu. Dua sampai tiga pertanyaan di awal biasanya cukup.

Kalau lupa sintaks fungsi tertentu gimana?

Bilang aja apa yang mau kamu capai, lalu tulis pendekatannya. Contohnya, "aku mau ambil median, di PostgreSQL biasanya pakai PERCENTILE_CONT, kalau salah sintaks tolong dikoreksi". Pewawancara nilai logikanya, bukan hafalanmu.

Lebih baik pakai CTE atau subquery di wawancara?

Pakai CTE. Blok WITH bikin query gampang dibaca dan gampang dijelasin langkah demi langkah, dan itu penting waktu kamu ngomong sambil nulis. Subquery bertumpuk susah diikuti pewawancara di layar kecil.

Soal SQL produk beda dari soal SQL biasa di mana?

Soal SQL biasa nguji sintaks: JOIN, GROUP BY, window function. Soal SQL produk nambahin lapisan definisi metrik: apa itu pengguna aktif, kapan seseorang dianggap churn, tanggal mana yang dipakai buat kohor. Query-nya sering lebih pendek, tapi asumsinya lebih banyak.

Harus hafal window function buat interview produk?

Minimal kenal ROW_NUMBER, LAG, dan SUM OVER. Tiga itu nutup sebagian besar kebutuhan: ambil kejadian pertama per pengguna, bandingin nilai hari ini sama kemarin, dan hitung total berjalan. Fungsi lain jarang jadi penentu di level junior sampai mid.

Rangkuman

Query yang jalan itu syarat minimum. Yang bikin kamu lolos adalah definisi metrik yang kamu pilih dan alasan di baliknya.

Latihan paling efektif: ambil satu soal di atas, tulis query-nya sambil ngomong keras, lalu tambahin satu kalimat soal keterbatasan angkamu.

Lanjut ke tahap berikutnya lewat transkrip mock interview studi kasus bisnis, atau langsung latihan nulis query di NgulikSQL tanpa perlu install database.

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

Cara Membuat Pivot Dinamis di SQL (Panduan 2026)
Tutorial SQL
19 Juli 2026•10 menit baca

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.

BimaBima
Menghitung YTD, QTD, dan MTD di SQL (Panduan 2026)
Tutorial SQL
17 Juli 2026•9 menit baca

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.

BimaBima
Gap and Island Analysis di SQL
Tutorial SQL
15 Juli 2026•10 menit baca

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.

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.

© 2026 Ngulik Data. Semua hak dilindungi.

TAUTAN
BantuanHargaDatasetBlogAfiliasi
LEGAL
Syarat & KetentuanKebijakan Privasi
Ngulik Data
DatasetLeaderboardBlogStore