| | 1 | = Advanced Reports = |
| | 2 | |
| | 3 | == Unit Demand Forecast — Quarterly Interest Ranking == |
| | 4 | |
| | 5 | Which currently available units show the strongest demand signals in the last quarter, |
| | 6 | and which buildings are generating the most interest for units. |
| | 7 | Each unit is scored by the inquiry count, appointment count. The units are ranked within their building, |
| | 8 | with the goal to give insight into potential buyer interest in what types of flats potential buyers are mostly looking for. |
| | 9 | |
| | 10 | === SQL === |
| | 11 | |
| | 12 | {{{ |
| | 13 | WITH unit_stats AS ( |
| | 14 | SELECT |
| | 15 | u.unit_id, |
| | 16 | u.unit_number, |
| | 17 | u.price, |
| | 18 | u.room_number, |
| | 19 | u.floor_area, |
| | 20 | f.floor_number, |
| | 21 | b.building_id, |
| | 22 | b.name AS building_name, |
| | 23 | COUNT(DISTINCT i.inquiry_id) AS total_inquiries, |
| | 24 | COUNT(DISTINCT a.appointment_id) AS total_appointments, |
| | 25 | ROUND( |
| | 26 | COUNT(DISTINCT a.appointment_id)::NUMERIC / |
| | 27 | NULLIF(COUNT(DISTINCT i.inquiry_id), 0) * 100, 2 |
| | 28 | ) AS conversion_rate_pct |
| | 29 | FROM project.unit u |
| | 30 | JOIN project.floor f ON u.floor_id = f.floor_id |
| | 31 | JOIN project.building b ON f.building_id = b.building_id |
| | 32 | LEFT JOIN project.inquiry i ON u.unit_id = i.unit_id |
| | 33 | AND i.created_at >= CURRENT_DATE - INTERVAL '3 months' |
| | 34 | LEFT JOIN project.appointment a ON u.unit_id = a.unit_id |
| | 35 | AND a.status = 'Scheduled' |
| | 36 | LEFT JOIN project.timeslot ts ON a.timeslot_id = ts.timeslot_id |
| | 37 | AND ts.date >= CURRENT_DATE - INTERVAL '3 months' |
| | 38 | WHERE u.status = 'Available' |
| | 39 | GROUP BY |
| | 40 | u.unit_id, u.unit_number, u.price, u.room_number, u.floor_area, |
| | 41 | f.floor_number, b.building_id, b.name |
| | 42 | ) |
| | 43 | SELECT |
| | 44 | building_name, |
| | 45 | unit_number, |
| | 46 | floor_number, |
| | 47 | room_number, |
| | 48 | floor_area, |
| | 49 | price, |
| | 50 | total_inquiries, |
| | 51 | total_appointments, |
| | 52 | conversion_rate_pct, |
| | 53 | (total_inquiries + total_appointments * 2) AS interest_score, |
| | 54 | RANK() OVER ( |
| | 55 | PARTITION BY building_id |
| | 56 | ORDER BY (total_inquiries + total_appointments * 2) DESC |
| | 57 | ) AS rank_in_building |
| | 58 | FROM unit_stats |
| | 59 | ORDER BY interest_score DESC, building_name, rank_in_building; |
| | 60 | }}} |
| | 61 | |
| | 62 | === Relational Algebra === |
| | 63 | |
| | 64 | Selection of available units and joining to floor and building |
| | 65 | |
| | 66 | {{{ |
| | 67 | AvailableUnits ← σ(status = 'Available')(Unit) |
| | 68 | |
| | 69 | UnitFloorBuilding ← AvailableUnits |
| | 70 | ⋈(unit.floor_id = floor.floor_id) Floor |
| | 71 | ⋈(floor.building_id = building.building_id) Building |
| | 72 | }}} |
| | 73 | |
| | 74 | Selecting recent inquires and scheduled appointments |
| | 75 | |
| | 76 | {{{ |
| | 77 | RecentInquiries ← σ(created_at ≥ CURRENT_DATE − 90)(Inquiry) |
| | 78 | |
| | 79 | RecentScheduledAppts ← σ(appointment.status = 'Scheduled' ∧ timeslot.date ≥ CURRENT_DATE − 90)( |
| | 80 | Appointment ⋈(appointment.timeslot_id = timeslot.timeslot_id) Timeslot |
| | 81 | ) |
| | 82 | }}} |
| | 83 | |
| | 84 | Left joining units to the inquires and appointments and per unit aggregation |
| | 85 | |
| | 86 | {{{ |
| | 87 | UnitWithActivity ← UnitFloorBuilding |
| | 88 | ⟕(unit.unit_id = inquiry.unit_id) RecentInquiries |
| | 89 | ⟕(unit.unit_id = appointment.unit_id) RecentScheduledAppts |
| | 90 | |
| | 91 | UnitStats ← γ( |
| | 92 | unit_id, unit_number, price, room_number, floor_area, |
| | 93 | floor_number, building_id, name ; |
| | 94 | COUNT(inquiry_id) → total_inquiries, |
| | 95 | COUNT(appointment_id) → total_appointments, |
| | 96 | COUNT(appointment_id) / NULLIF(COUNT(inquiry_id), 0) * 100 |
| | 97 | → conversion_rate_pct |
| | 98 | )(UnitWithActivity) |
| | 99 | }}} |
| | 100 | |
| | 101 | Interest score, ranking within building, and final columns |
| | 102 | |
| | 103 | {{{ |
| | 104 | Scored ← ρ( |
| | 105 | interest_score ← total_inquiries + total_appointments · 2, |
| | 106 | rank_in_building ← RANK() OVER (PARTITION BY building_id |
| | 107 | ORDER BY interest_score DESC) |
| | 108 | )(UnitStats) |
| | 109 | |
| | 110 | Result ← τ(interest_score DESC, name, rank_in_building)(Scored) |
| | 111 | |
| | 112 | π(name, unit_number, floor_number, room_number, floor_area, |
| | 113 | price, total_inquiries, total_appointments, |
| | 114 | conversion_rate_pct, interest_score, rank_in_building)(Result) |
| | 115 | }}} |
| | 116 | |
| | 117 | ---- |