AdvancedReports: advanced_reports.sql

File advanced_reports.sql, 3.6 KB (added by 183164, 12 days ago)
Line 
1-- CityFix - напредни извештаи (фаза P6)
2SET search_path TO project;
3
4-- Извештај 1: Квартален учинок во решавањето на пријавите по категорија
5WITH 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),
14per_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)
24SELECT 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
33FROM per_quarter pq
34JOIN categories c ON c.category_id = pq.category_id
35LEFT JOIN per_quarter prev
36 ON prev.category_id = pq.category_id
37 AND prev.quarter = pq.quarter - INTERVAL '3 months'
38ORDER BY pq.quarter, slowest_rank;
39
40-- Извештај 2: Жаришта на повторувачки проблеми
41WITH 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),
46located 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)
56SELECT 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
66FROM located l
67JOIN categories c ON c.category_id = l.category_id
68GROUP BY l.cell_lat, l.cell_lon, c.name
69HAVING COUNT(*) >= 3
70 AND COUNT(DISTINCT date_trunc('quarter', l.created_at)) >= 2
71ORDER BY hotspot_rank, reports DESC;