Login 3 Hari Berturut-turut
Pertanyaan
"Cari user yang pernah login tiga hari berturut-turut. Tampilkan juga tanggal mulai rangkaian tiga hari pertamanya."
Tabel login:
| login_id | user_id | waktu_login |
|---|---|---|
| 1 | U01 | 2026-09-01 07:10:00 |
| 2 | U01 | 2026-09-02 12:00:00 |
| 3 | U02 | 2026-09-01 20:00:00 |
| 4 | U01 | 2026-09-02 22:30:00 |
| 5 | U02 | 2026-09-02 09:15:00 |
| 6 | U01 | 2026-09-03 06:45:00 |
| 7 | U02 | 2026-09-04 10:00:00 |
| 8 | U03 | 2026-09-05 19:20:00 |
Jawaban Singkat
Ubah dulu data login jadi satu baris per user per tanggal (DISTINCT + CAST ke DATE), karena user bisa login berkali-kali sehari. Lalu untuk setiap tanggal, lihat dua tanggal login berikutnya dengan LEAD(tanggal, 1) dan LEAD(tanggal, 2). Kalau keduanya persis tanggal + 1 dan tanggal + 2, berarti tiga hari berturut-turut.
Pembahasan
- Turunkan grain ke hari. U01 login dua kali pada 2 September. Kalau tidak di-dedup, baris berikutnya dari 1 September adalah login kedua di 2 September, bukan 3 September, sehingga rangkaiannya tidak terdeteksi.
- Intip ke depan dengan
LEAD.LEAD(tanggal, 1)adalah tanggal login berikutnya,LEAD(tanggal, 2)tanggal login setelahnya, dihitung per user (PARTITION BY user_id). - Cek berturut-turut. Syaratnya
tanggal_2 = tanggal + 1dantanggal_3 = tanggal + 2. MenjumlahkanDATEdengan integer menghasilkan tanggal sekian hari kemudian. - Ringkas per user. User yang login 4 hari berturut-turut akan lolos di dua baris (hari ke-1 dan ke-2).
GROUP BY user_iddenganMIN(tanggal)meringkasnya jadi satu baris dan sekaligus memberi tanggal mulai rangkaian pertama.
U02 login 1, 2, lalu 4 September. Bolong di tanggal 3, jadi tidak lolos. U03 hanya login sekali.
Ini yang terjadi kalau langkah 1 dilewati dan LEAD dihitung langsung dari tabel login untuk U01:
| tanggal | tanggal_2 | tanggal_3 |
|---|---|---|
| 2026-09-01 | 2026-09-02 | 2026-09-02 |
| 2026-09-02 | 2026-09-02 | 2026-09-03 |
| 2026-09-02 | 2026-09-03 | NULL |
| 2026-09-03 | NULL | NULL |
Tidak ada satu baris pun yang memenuhi syarat, sehingga U01 hilang dari hasil.
Query
WITH hari_login AS ( SELECT DISTINCT user_id, CAST(waktu_login AS DATE) AS tanggal FROM login ), dengan_berikutnya AS ( SELECT user_id, tanggal, LEAD(tanggal, 1) OVER (PARTITION BY user_id ORDER BY tanggal) AS tanggal_2, LEAD(tanggal, 2) OVER (PARTITION BY user_id ORDER BY tanggal) AS tanggal_3 FROM hari_login ) SELECT user_id, MIN(tanggal) AS mulai_3_hari_pertama FROM dengan_berikutnya WHERE tanggal_2 = tanggal + 1 AND tanggal_3 = tanggal + 2 GROUP BY user_id ORDER BY user_id;
Contoh Output
| user_id | mulai_3_hari_pertama |
|---|---|
| U01 | 2026-09-01 |
Jebakan Umum
- Tidak men-dedup login per hari. Login ganda di hari yang sama merusak perbandingan
LEAD. - Membandingkan timestamp, bukan tanggal.
2026-09-02 12:00:00tidak sama dengan2026-09-01 07:10:00 + 1 hari. - Hanya mengecek
LEAD(tanggal, 2) = tanggal + 2. Kalau sudah di-dedup memang cukup (tanggal unik dan naik, jadi tanggal di antaranya pastitanggal + 1), tapi kandidat sering memakai cara ini tanpa dedup dan hasilnya salah. - Lupa
PARTITION BY user_id, sehingga login user lain dianggap sebagai "hari berikutnya".
Follow-up dari Interviewer
- "Kalau syaratnya N hari berturut-turut, dengan N bisa diganti?" Menulis
LEADsebanyak N kali tidak praktis. Pakai teknik gaps and islands:tanggal - ROW_NUMBER()per user menghasilkan nilai yang sama untuk tanggal-tanggal yang berurutan, laluGROUP BYnilai itu danHAVING COUNT(*) >= N. Lihat soal I94. - "Login yang dihitung harus dalam zona waktu WIB, padahal data tersimpan UTC." Konversi dulu sebelum
CASTkeDATE. Login pukul 20:00 UTC sudah masuk tanggal berikutnya di WIB. - "Berapa persen user aktif bulan ini yang pernah 3 hari berturut-turut?" Hitung jumlah user dari query ini, bagi dengan
COUNT(DISTINCT user_id)login bulan yang sama.
Yang Sebenarnya Diuji
Soal "hari berturut-turut" adalah pintu masuk ke pola gaps and islands. Interviewer ingin melihat apakah kamu sadar perlu menurunkan grain ke harian, bisa memakai LEAD/LAG dengan partisi yang benar, dan tahu cara memperluasnya ke N hari.
Catatan Dialect
tanggal + 1pada tipeDATEjalan di DuckDB dan PostgreSQL.- MySQL:
DATE_ADD(tanggal, INTERVAL 1 DAY).CAST(waktu_login AS DATE)tetap diterima, atau pakaiDATE(waktu_login). - BigQuery:
DATE_ADD(tanggal, INTERVAL 1 DAY).