From 4e7878d4179abf19f9948956dbdb433bc2e522bb Mon Sep 17 00:00:00 2001 From: mwpn Date: Wed, 17 Dec 2025 17:43:55 +0700 Subject: [PATCH] Add explanation: hourly summary data is REPLACED not ADDED (upsert behavior) --- UPSERT_BEHAVIOR.md | 186 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 UPSERT_BEHAVIOR.md diff --git a/UPSERT_BEHAVIOR.md b/UPSERT_BEHAVIOR.md new file mode 100644 index 0000000..c06cb80 --- /dev/null +++ b/UPSERT_BEHAVIOR.md @@ -0,0 +1,186 @@ +# Penjelasan Behavior Upsert di Hourly Summary + +## Jawaban Singkat + +**Data DIGANTI (REPLACE), bukan ditambah.** + +## Detail Penjelasan + +### Query Upsert yang Digunakan + +```sql +INSERT INTO hourly_summary + (summary_date, summary_hour, location_code, gate_code, category, total_count, total_amount) +VALUES (?, ?, ?, ?, ?, ?, ?) +ON DUPLICATE KEY UPDATE + total_count = VALUES(total_count), + total_amount = VALUES(total_amount) +``` + +### Primary Key + +```sql +PRIMARY KEY (summary_date, summary_hour, location_code, gate_code, category) +``` + +### Behavior: ON DUPLICATE KEY UPDATE + +**Jika row BELUM ADA:** +- ✅ **INSERT** → Tambah row baru + +**Jika row SUDAH ADA:** +- ✅ **UPDATE** → Ganti `total_count` dan `total_amount` dengan nilai baru +- ❌ **BUKAN** tambah ke nilai lama + +## Contoh Skenario + +### Skenario 1: Cron Pertama Kali (Row Belum Ada) + +**Jam 2:00, cron jalan untuk update jam 1:00:** + +``` +1. Query entry_events untuk jam 1:00: + - location_code: kerkof_01 + - gate_code: gate01 + - category: motor + - COUNT: 10 events + - total_amount: 10 × 2000 = 20000 + +2. INSERT ke hourly_summary: + ✅ Row baru dibuat: + summary_date: 2025-12-17 + summary_hour: 1 + location_code: kerkof_01 + gate_code: gate01 + category: motor + total_count: 10 + total_amount: 20000 +``` + +### Skenario 2: Cron Kedua Kali (Row Sudah Ada) + +**Jam 2:30, ada event baru masuk (terlambat):** +- Event jam 1:00 masuk di jam 2:30 (terlambat) + +**Jam 3:00, cron jalan lagi untuk update jam 1:00:** + +``` +1. Query entry_events untuk jam 1:00 (SEKARANG): + - location_code: kerkof_01 + - gate_code: gate01 + - category: motor + - COUNT: 11 events (termasuk yang terlambat) + - total_amount: 11 × 2000 = 22000 + +2. ON DUPLICATE KEY UPDATE: + ✅ Row LAMA diganti: + - total_count: 10 → 11 (DIGANTI, bukan 10 + 11 = 21) + - total_amount: 20000 → 22000 (DIGANTI, bukan 20000 + 22000 = 42000) +``` + +## Mengapa Diganti, Bukan Ditambah? + +### 1. **Akurasi Data** +- Summary harus selalu mencerminkan data aktual di `entry_events` +- Jika ditambah, data akan double-count jika cron jalan berulang + +### 2. **Idempotent** +- Cron bisa jalan berulang tanpa merusak data +- Hasil selalu sama, tidak peduli berapa kali dijalankan + +### 3. **Event Terlambat** +- Jika ada event yang masuk terlambat, akan otomatis terhitung saat rekap ulang +- Tidak perlu manual correction + +## Contoh Timeline Lengkap + +### Hari: 2025-12-17 + +**Jam 1:00 - 1:59:** +``` +Event masuk ke entry_events: +- 1:05 → motor (kerkof_01, gate01) +- 1:15 → motor (kerkof_01, gate01) +- 1:30 → motor (kerkof_01, gate01) +Total: 3 events +``` + +**Jam 2:00 - Cron jalan:** +``` +1. Query entry_events untuk jam 1:00: + → COUNT: 3 events + → total_amount: 3 × 2000 = 6000 + +2. INSERT ke hourly_summary: + ✅ Row baru: total_count = 3, total_amount = 6000 +``` + +**Jam 2:30 - Event terlambat masuk:** +``` +Event masuk ke entry_events (terlambat): +- 2:30 → motor (kerkof_01, gate01) dengan event_time = 1:45 +Total sekarang: 4 events untuk jam 1:00 +``` + +**Jam 3:00 - Cron jalan lagi (opsional, jika rekap ulang):** +``` +1. Query entry_events untuk jam 1:00 (SEKARANG): + → COUNT: 4 events (termasuk yang terlambat) + → total_amount: 4 × 2000 = 8000 + +2. ON DUPLICATE KEY UPDATE: + ✅ Row LAMA diganti: + - total_count: 3 → 4 (DIGANTI) + - total_amount: 6000 → 8000 (DIGANTI) +``` + +## Verifikasi di Database + +### Cek Data Sebelum Cron: + +```sql +SELECT * FROM hourly_summary +WHERE summary_date = '2025-12-17' +AND summary_hour = 1 +AND location_code = 'kerkof_01' +AND gate_code = 'gate01' +AND category = 'motor'; + +-- Hasil: +-- total_count: 3 +-- total_amount: 6000 +``` + +### Jalankan Cron: + +```bash +php bin/hourly_summary.php today 1 +``` + +### Cek Data Setelah Cron: + +```sql +SELECT * FROM hourly_summary +WHERE summary_date = '2025-12-17' +AND summary_hour = 1 +AND location_code = 'kerkof_01' +AND gate_code = 'gate01' +AND category = 'motor'; + +-- Hasil (jika ada event baru): +-- total_count: 4 (DIGANTI dari 3, bukan 3 + 4 = 7) +-- total_amount: 8000 (DIGANTI dari 6000, bukan 6000 + 8000 = 14000) +``` + +## Kesimpulan + +| Aspek | Behavior | +|-------|----------| +| **Jika row belum ada** | ✅ INSERT (tambah baru) | +| **Jika row sudah ada** | ✅ UPDATE (ganti nilai) | +| **Apakah ditambah?** | ❌ TIDAK, diganti | +| **Apakah diganti?** | ✅ YA, diganti dengan nilai baru | +| **Nilai lama** | ❌ Tidak dipertahankan, diganti dengan hasil rekap ulang | + +**Intinya:** Data selalu di-rekap ulang dari `entry_events`, bukan ditambah ke nilai lama. Ini memastikan akurasi dan konsistensi data summary. +