| 1 | -- CityFix - напредни извештаи (фаза P6)
|
|---|
| 2 | SET search_path TO project;
|
|---|
| 3 |
|
|---|
| 4 | -- Извештај 1: Квартален учинок во решавањето на пријавите по категорија
|
|---|
| 5 | WITH report_times AS (
|
|---|
| 6 | SELECT r.report_id, r.category_id, r.status, r.created_at,
|
|---|
| 7 | date_trunc('quarter', r.created_at) AS quarter,
|
|---|
| 8 | MIN(l.changed_at) FILTER (WHERE l.status = 'received') AS received_at,
|
|---|
| 9 | MIN(l.changed_at) FILTER (WHERE l.status = 'resolved') AS resolved_at
|
|---|
| 10 | FROM reports r
|
|---|
| 11 | JOIN status_logs l ON l.report_id = r.report_id
|
|---|
| 12 | GROUP BY r.report_id
|
|---|
| 13 | ),
|
|---|
| 14 | per_quarter AS (
|
|---|
| 15 | SELECT quarter, category_id,
|
|---|
| 16 | COUNT(*) AS total,
|
|---|
| 17 | COUNT(*) FILTER (WHERE status = 'resolved') AS resolved,
|
|---|
| 18 | COUNT(*) FILTER (WHERE status = 'rejected') AS rejected,
|
|---|
| 19 | AVG(EXTRACT(EPOCH FROM received_at - created_at) / 3600) AS avg_response_hours,
|
|---|
| 20 | AVG(EXTRACT(EPOCH FROM resolved_at - created_at) / 86400) AS avg_resolution_days
|
|---|
| 21 | FROM report_times
|
|---|
| 22 | GROUP BY quarter, category_id
|
|---|
| 23 | )
|
|---|
| 24 | SELECT to_char(pq.quarter, 'YYYY-"Q"Q') AS quarter,
|
|---|
| 25 | c.name AS category,
|
|---|
| 26 | pq.total, pq.resolved, pq.rejected,
|
|---|
| 27 | ROUND(100.0 * pq.resolved / pq.total, 1) AS resolved_pct,
|
|---|
| 28 | ROUND(pq.avg_response_hours, 1) AS avg_response_hours,
|
|---|
| 29 | ROUND(pq.avg_resolution_days, 1) AS avg_resolution_days,
|
|---|
| 30 | ROUND(pq.avg_resolution_days - prev.avg_resolution_days, 1) AS change_vs_prev_quarter,
|
|---|
| 31 | RANK() OVER (PARTITION BY pq.quarter
|
|---|
| 32 | ORDER BY pq.avg_resolution_days DESC NULLS LAST) AS slowest_rank
|
|---|
| 33 | FROM per_quarter pq
|
|---|
| 34 | JOIN categories c ON c.category_id = pq.category_id
|
|---|
| 35 | LEFT JOIN per_quarter prev
|
|---|
| 36 | ON prev.category_id = pq.category_id
|
|---|
| 37 | AND prev.quarter = pq.quarter - INTERVAL '3 months'
|
|---|
| 38 | ORDER BY pq.quarter, slowest_rank;
|
|---|
| 39 |
|
|---|
| 40 | -- Извештај 2: Жаришта на повторувачки проблеми
|
|---|
| 41 | WITH resolution AS (
|
|---|
| 42 | SELECT report_id, MIN(changed_at) FILTER (WHERE status = 'resolved') AS resolved_at
|
|---|
| 43 | FROM status_logs
|
|---|
| 44 | GROUP BY report_id
|
|---|
| 45 | ),
|
|---|
| 46 | located AS (
|
|---|
| 47 | SELECT r.report_id, r.category_id, r.citizen_id, r.status, r.created_at, r.location_text,
|
|---|
| 48 | ROUND(r.latitude / 0.005) * 0.005 AS cell_lat,
|
|---|
| 49 | ROUND(r.longitude / 0.005) * 0.005 AS cell_lon,
|
|---|
| 50 | res.resolved_at
|
|---|
| 51 | FROM reports r
|
|---|
| 52 | JOIN resolution res ON res.report_id = r.report_id
|
|---|
| 53 | WHERE r.latitude IS NOT NULL
|
|---|
| 54 | AND r.status <> 'rejected'
|
|---|
| 55 | )
|
|---|
| 56 | SELECT RANK() OVER (ORDER BY COUNT(*) * COUNT(DISTINCT date_trunc('quarter', l.created_at)) DESC) AS hotspot_rank,
|
|---|
| 57 | l.cell_lat, l.cell_lon,
|
|---|
| 58 | c.name AS category,
|
|---|
| 59 | MAX(l.location_text) AS example_address,
|
|---|
| 60 | COUNT(*) AS reports,
|
|---|
| 61 | COUNT(DISTINCT l.citizen_id) AS distinct_citizens,
|
|---|
| 62 | COUNT(DISTINCT date_trunc('quarter', l.created_at)) AS quarters_with_reports,
|
|---|
| 63 | COUNT(*) FILTER (WHERE l.status NOT IN ('resolved', 'rejected')) AS open_now,
|
|---|
| 64 | ROUND(AVG(EXTRACT(EPOCH FROM l.resolved_at - l.created_at) / 86400), 1) AS avg_resolution_days,
|
|---|
| 65 | to_char(MAX(l.created_at), 'DD.MM.YYYY') AS last_report
|
|---|
| 66 | FROM located l
|
|---|
| 67 | JOIN categories c ON c.category_id = l.category_id
|
|---|
| 68 | GROUP BY l.cell_lat, l.cell_lon, c.name
|
|---|
| 69 | HAVING COUNT(*) >= 3
|
|---|
| 70 | AND COUNT(DISTINCT date_trunc('quarter', l.created_at)) >= 2
|
|---|
| 71 | ORDER BY hotspot_rank, reports DESC;
|
|---|