Changes between Version 1 and Version 2 of AdvancedReports


Ignore:
Timestamp:
07/03/26 13:17:13 (7 days ago)
Author:
223091
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • AdvancedReports

    v1 v2  
    11= Advanced Reports =
    22
    3 This page documents Phase P6 of the Room Reservation System project. The goal of this phase is to define and implement more complex analytical database reports using SQL. The reports are designed to provide a higher-level picture of the long-term operation of the reservation system.
    4 
    5 The project has one team member, therefore two advanced analytical reports are implemented.
    6 
    7 The reports are based on the relational schema created in Phase P2 and confirmed through the normalization process in Phase P5.
    8 
    9 == Report 1: Quarterly room utilization and approval report ==
     3This page documents two complex analytical database reports for the Room Reservation System. The reports are written as SQL queries over the implemented PostgreSQL schema in the ''project'' schema. Each report uses several joined relations, grouping, aggregate calculations, conditional aggregation, derived indicators, and ranking in order to provide useful analytical information about the long-term operation of the reservation system.
     4
     5The selected reports are:
     6
     7* Quarterly room utilization and reservation status report
     8* Quarterly equipment demand and stock pressure report
     9
     10Both reports are intended to support administrative decision-making. They can be used by a resource administrator or reservation approver to understand how rooms and equipment are used over time, which rooms are most frequently requested, and which equipment types may require additional stock.
     11
     12== Report 1: Quarterly room utilization and reservation status report ==
     13
     14=== Data requirements idea / concept title ===
     15
     16Quarterly room utilization and reservation status report
    1017
    1118=== Data requirements description ===
    1219
    13 This report analyzes how rooms are used over a longer period of time. It groups reservations by quarter, building, and room, and calculates the number of reservation requests, the number of approved, rejected, cancelled, and pending reservations, the total requested hours, and the approved reservation hours.
    14 
    15 The report is useful for identifying:
    16 
    17 * which rooms are used most often,
    18 * which rooms have the highest approved reservation time,
    19 * how much demand exists for each room,
    20 * whether some rooms are frequently requested but not approved,
    21 * which rooms are important resources in the organization.
    22 
    23 This report can be used on a quarterly, annual, or multi-year level. In the current query, the report is shown for the year 2026.
     20This report analyzes how rooms are used during a selected year, grouped by quarter, building, and room. It calculates how many reservations were made for each room, how many of them were approved, rejected, cancelled, or still pending, and how many total hours were requested and approved.
     21
     22The report is useful because it shows which rooms are used most often and which rooms may be underused. It also helps the organization identify whether certain buildings or room types have higher reservation demand. Since the report is grouped by quarter, it can be used for long-term analysis of room usage trends.
     23
     24The report uses data from the following relations:
     25
     26* ''project.reservations''
     27* ''project.rooms''
     28* ''project.buildings''
     29
     30The report performs the following operations:
     31
     32* joins reservations with rooms and buildings;
     33* filters room-based reservations only;
     34* groups reservations by quarter, building, and room;
     35* counts total reservations;
     36* counts reservations by status using conditional aggregation;
     37* calculates requested and approved reservation hours;
     38* calculates each room's share of approved hours within the quarter;
     39* ranks rooms by utilization within each quarter.
    2440
    2541=== Solution SQL ===
    2642
    2743{{{
    28 WITH reservation_base AS (
    29 SELECT
    30 b.building_id,
     44WITH room_reservation_base AS (
     45SELECT
     46date_trunc('quarter', res.reservation_date)::date AS quarter_start,
    3147b.name AS building_name,
    3248r.room_id,
     
    3652res.reservation_id,
    3753res.status,
    38 DATE_TRUNC('quarter', res.reservation_date)::date AS quarter_start,
    39 EXTRACT(EPOCH FROM (res.end_time - res.start_time)) / 3600.0 AS duration_hours
     54EXTRACT(EPOCH FROM (res.end_time - res.start_time)) / 3600.0 AS reservation_hours
    4055FROM project.reservations res
    4156JOIN project.rooms r
     
    4358JOIN project.buildings b
    4459ON r.building_id = b.building_id
    45 WHERE res.reservation_date >= DATE '2026-01-01'
     60WHERE res.room_id IS NOT NULL
     61AND res.reservation_date >= DATE '2026-01-01'
    4662AND res.reservation_date < DATE '2027-01-01'
    4763),
    48 room_report AS (
     64room_quarter_summary AS (
    4965SELECT
    5066quarter_start,
    5167building_name,
     68room_id,
    5269room_code,
    5370type,
    5471capacity,
    55 COUNT(*) AS total_room_reservations,
     72COUNT(reservation_id) AS total_room_reservations,
    5673COUNT(*) FILTER (WHERE status = 'approved') AS approved_reservations,
    5774COUNT(*) FILTER (WHERE status = 'rejected') AS rejected_reservations,
    5875COUNT(*) FILTER (WHERE status = 'cancelled') AS cancelled_reservations,
    5976COUNT(*) FILTER (WHERE status = 'pending') AS pending_reservations,
    60 ROUND(COALESCE(SUM(duration_hours), 0)::numeric, 2) AS requested_hours,
    61 ROUND(COALESCE(SUM(duration_hours) FILTER (WHERE status = 'approved'), 0)::numeric, 2) AS approved_hours,
    62 ROUND(
    63 (100.0 * COUNT(*) FILTER (WHERE status = 'approved') / NULLIF(COUNT(*), 0))::numeric,
    64 2
    65 ) AS approval_rate_percent
    66 FROM reservation_base
     77ROUND(SUM(reservation_hours), 2) AS requested_hours,
     78ROUND(COALESCE(SUM(reservation_hours) FILTER (WHERE status = 'approved'), 0), 2) AS approved_hours
     79FROM room_reservation_base
    6780GROUP BY
    6881quarter_start,
    6982building_name,
     83room_id,
    7084room_code,
    7185type,
    7286capacity
    73 )
     87),
     88room_quarter_ranked AS (
    7489SELECT
    7590quarter_start,
     
    85100requested_hours,
    86101approved_hours,
    87 approval_rate_percent,
    88 RANK() OVER (
     102ROUND(
     103approved_hours / NULLIF(SUM(approved_hours) OVER (PARTITION BY quarter_start), 0) * 100,
     1042
     105) AS approved_hours_share_percent,
     106DENSE_RANK() OVER (
    89107PARTITION BY quarter_start
    90 ORDER BY approved_hours DESC, total_room_reservations DESC, capacity DESC
    91 ) AS utilization_rank_in_quarter
    92 FROM room_report
     108ORDER BY approved_hours DESC, total_room_reservations DESC, room_code
     109) AS utilization_rank,
     110CASE
     111WHEN approved_hours >= 4 THEN 'high_usage'
     112WHEN approved_hours >= 2 THEN 'medium_usage'
     113WHEN approved_hours > 0 THEN 'low_usage'
     114ELSE 'no_approved_usage'
     115END AS utilization_level
     116FROM room_quarter_summary
     117)
     118SELECT
     119quarter_start,
     120building_name,
     121room_code,
     122type,
     123capacity,
     124total_room_reservations,
     125approved_reservations,
     126rejected_reservations,
     127cancelled_reservations,
     128pending_reservations,
     129requested_hours,
     130approved_hours,
     131approved_hours_share_percent,
     132utilization_rank,
     133utilization_level
     134FROM room_quarter_ranked
    93135ORDER BY
    94136quarter_start,
    95 utilization_rank_in_quarter,
     137utilization_rank,
    96138building_name,
    97139room_code;
    98140}}}
    99141
    100 === Explanation of the SQL solution ===
    101 
    102 The query first creates a temporary result named ''reservation_base''. This part joins reservations, rooms, and buildings, and calculates the duration of each room reservation in hours.
    103 
    104 The second temporary result, ''room_report'', groups the data by quarter, building, room, room type, and capacity. It calculates aggregate values such as the total number of room reservations, the number of approved reservations, the number of rejected reservations, the number of cancelled reservations, the number of pending reservations, the total requested hours, and the approved hours.
    105 
    106 The final SELECT adds a ranking value using the SQL window function RANK(). Rooms are ranked inside each quarter according to approved reservation hours, number of reservations, and capacity.
    107 
    108 This makes the report analytical because it combines joins, filtering, grouping, conditional aggregation, duration calculation, and window ranking.
    109 
    110142=== Solution Relational Algebra ===
    111143
    112 The following relational algebra expression uses extended relational algebra because the report requires grouping and aggregate functions.
     144The report can be represented using extended relational algebra because it uses grouping, aggregation, conditional aggregation, and ranking.
    113145
    114146Let:
    115147
    116 * Reservations = Res
    117 * Rooms = R
    118 * Buildings = B
    119 
    120 First, create the joined reservation-room-building relation:
    121 
    122 {{{
    123 RB =
    124 σ_{reservation_date >= '2026-01-01' ∧ reservation_date < '2027-01-01'}
    125 (
    126 Res ⋈*{Res.room_id = R.room_id} R
    127 ⋈*{R.building_id = B.building_id} B
    128 )
    129 }}}
    130 
    131 Then calculate grouped room utilization statistics:
    132 
    133 {{{
    134 RoomReport =
    135 γ_{quarter(reservation_date), B.name, R.room_code, R.type, R.capacity;
     148* ''RES'' = Reservations
     149* ''R'' = Rooms
     150* ''B'' = Buildings
     151
     152First, select only room-based reservations in the selected period:
     153
     154{{{
     155A =
     156σ room_id IS NOT NULL AND reservation_date >= '2026-01-01' AND reservation_date < '2027-01-01'
     157(RES)
     158}}}
     159
     160Then join reservations with rooms and buildings:
     161
     162{{{
     163B1 =
     164A ⨝ A.room_id = R.room_id R
     165}}}
     166
     167{{{
     168B2 =
     169B1 ⨝ R.building_id = B.building_id B
     170}}}
     171
     172Then group the result by quarter, building, room, room type, and capacity:
     173
     174{{{
     175C =
     176γ quarter_start, building_name, room_id, room_code, type, capacity;
    136177COUNT(reservation_id) → total_room_reservations,
    137 COUNT_{status = 'approved'}(reservation_id) → approved_reservations,
    138 COUNT_{status = 'rejected'}(reservation_id) → rejected_reservations,
    139 COUNT_{status = 'cancelled'}(reservation_id) → cancelled_reservations,
    140 COUNT_{status = 'pending'}(reservation_id) → pending_reservations,
     178COUNT(status = 'approved') → approved_reservations,
     179COUNT(status = 'rejected') → rejected_reservations,
     180COUNT(status = 'cancelled') → cancelled_reservations,
     181COUNT(status = 'pending') → pending_reservations,
    141182SUM(end_time - start_time) → requested_hours,
    142 SUM_{status = 'approved'}(end_time - start_time) → approved_hours
    143 }
    144 (RB)
    145 }}}
    146 
    147 Finally, extend the grouped relation with an approval rate and a quarterly utilization ranking:
     183SUM(end_time - start_time WHERE status = 'approved') → approved_hours
     184(B2)
     185}}}
     186
     187Finally, extended relational algebra is used to calculate the percentage share of approved hours and the utilization rank for each room inside the same quarter:
    148188
    149189{{{
    150190Result =
    151 ρ_{approval_rate_percent, utilization_rank_in_quarter}
    152 (RoomReport)
    153 }}}
    154 
    155 The report preserves the meaning of the original relations because every joined tuple represents a reservation connected to exactly one room and one building.
    156 
    157 == Report 2: Quarterly equipment demand and replenishment report ==
     191ρ approved_hours_share_percent, utilization_rank, utilization_level
     192(C)
     193}}}
     194
     195This corresponds to the SQL query where window functions and CASE expressions are used for ranking and classification.
     196
     197=== Report result screenshot ===
     198
     199The following screenshot shows the result of executing the first report in DBeaver.
     200
     201[[Image(report1_room_utilization.png, width=100%)]]
     202
     203''Figure 1. Quarterly room utilization report showing room reservations grouped by quarter, building, room, room type, capacity, reservation status, requested hours, and utilization ranking.''
     204
     205=== Discussion ===
     206
     207The first report shows how each room is used during each quarter. The result includes the number of reservations, the number of approved, rejected, cancelled, and pending reservations, and the number of requested and approved reservation hours.
     208
     209This report is useful for identifying rooms with high demand and rooms that are rarely used. If a room has a high utilization rank and many approved hours, the organization may consider increasing availability of similar rooms or assigning more equipment to that room type. If a room has very low usage, the organization may investigate whether its capacity, type, location, or equipment availability is not suitable for users.
     210
     211== Report 2: Quarterly equipment demand and stock pressure report ==
     212
     213=== Data requirements idea / concept title ===
     214
     215Quarterly equipment demand and stock pressure report
    158216
    159217=== Data requirements description ===
    160218
    161 This report analyzes how often equipment is requested as part of reservations and compares that demand with the available equipment quantity in the system. It combines equipment from general stock and equipment assigned to specific rooms.
    162 
    163 The report is useful for identifying:
    164 
    165 * which equipment is requested most often,
    166 * which equipment has high demand compared to available quantity,
    167 * whether equipment demand increases or decreases between quarters,
    168 * which equipment types should be considered for replenishment,
    169 * whether the organization has enough available equipment for future reservations.
    170 
    171 This report can support planning and decision-making for equipment purchasing and resource management.
     219This report analyzes equipment demand during a selected year, grouped by quarter and equipment type. It compares the number of requested equipment items with the registered stock quantity and the equipment assigned to rooms. It also calculates how much demand was approved, pending, or rejected.
     220
     221The report is useful because it helps the organization understand which equipment types are requested most often and whether the existing stock is sufficient. It can support decisions about purchasing new equipment, moving equipment between rooms, or increasing the stock of frequently requested equipment.
     222
     223The report uses data from the following relations:
     224
     225* ''project.equipment''
     226* ''project.room_equipment''
     227* ''project.reservation_equipment''
     228* ''project.reservations''
     229
     230The report performs the following operations:
     231
     232* calculates how much equipment is assigned to rooms;
     233* joins requested equipment with reservations and equipment data;
     234* groups equipment demand by quarter and equipment type;
     235* calculates total requested quantity;
     236* calculates approved, pending, rejected, and cancelled requested quantities;
     237* compares demand with total registered quantity;
     238* calculates demand ratio;
     239* compares demand with the previous quarter;
     240* ranks equipment by demand in each quarter;
     241* classifies demand level as critical, high, medium, or low.
    172242
    173243=== Solution SQL ===
     
    176246WITH room_stock AS (
    177247SELECT
    178 equipment_id,
    179 SUM(quantity) AS assigned_room_quantity
    180 FROM project.room_equipment
    181 GROUP BY equipment_id
     248re.equipment_id,
     249SUM(re.quantity) AS assigned_room_quantity
     250FROM project.room_equipment re
     251GROUP BY re.equipment_id
    182252),
    183253equipment_demand AS (
    184254SELECT
     255date_trunc('quarter', res.reservation_date)::date AS quarter_start,
    185256e.equipment_id,
    186257e.name AS equipment_name,
     
    188259COALESCE(rs.assigned_room_quantity, 0) AS assigned_room_quantity,
    189260e.stock_quantity + COALESCE(rs.assigned_room_quantity, 0) AS total_registered_quantity,
    190 DATE_TRUNC('quarter', res.reservation_date)::date AS quarter_start,
    191 COUNT(DISTINCT re.reservation_id) AS reservations_with_equipment,
    192 COALESCE(SUM(re.requested_quantity), 0) AS total_requested_quantity,
    193 COALESCE(SUM(re.requested_quantity) FILTER (WHERE res.status = 'approved'), 0) AS approved_requested_quantity,
    194 COALESCE(SUM(re.requested_quantity) FILTER (WHERE res.status = 'pending'), 0) AS pending_requested_quantity,
    195 COALESCE(SUM(re.requested_quantity) FILTER (WHERE res.status = 'rejected'), 0) AS rejected_requested_quantity
    196 FROM project.equipment e
     261COUNT(DISTINCT res.reservation_id) AS reservations_with_equipment,
     262SUM(req.requested_quantity) AS total_requested_quantity,
     263COALESCE(SUM(req.requested_quantity) FILTER (WHERE res.status = 'approved'), 0) AS approved_requested_quantity,
     264COALESCE(SUM(req.requested_quantity) FILTER (WHERE res.status = 'pending'), 0) AS pending_requested_quantity,
     265COALESCE(SUM(req.requested_quantity) FILTER (WHERE res.status = 'rejected'), 0) AS rejected_requested_quantity,
     266COALESCE(SUM(req.requested_quantity) FILTER (WHERE res.status = 'cancelled'), 0) AS cancelled_requested_quantity
     267FROM project.reservation_equipment req
     268JOIN project.reservations res
     269ON req.reservation_id = res.reservation_id
     270JOIN project.equipment e
     271ON req.equipment_id = e.equipment_id
    197272LEFT JOIN room_stock rs
    198 ON rs.equipment_id = e.equipment_id
    199 LEFT JOIN project.reservation_equipment re
    200 ON re.equipment_id = e.equipment_id
    201 LEFT JOIN project.reservations res
    202 ON res.reservation_id = re.reservation_id
    203 WHERE res.reservation_date IS NULL
    204 OR (
    205 res.reservation_date >= DATE '2026-01-01'
     273ON e.equipment_id = rs.equipment_id
     274WHERE res.reservation_date >= DATE '2026-01-01'
    206275AND res.reservation_date < DATE '2027-01-01'
    207 )
    208276GROUP BY
     277date_trunc('quarter', res.reservation_date)::date,
    209278e.equipment_id,
    210279e.name,
    211280e.stock_quantity,
    212 rs.assigned_room_quantity,
    213 DATE_TRUNC('quarter', res.reservation_date)::date
     281rs.assigned_room_quantity
    214282),
    215 equipment_analysis AS (
    216 SELECT
    217 *,
    218 ROUND(
    219 (total_requested_quantity::numeric / NULLIF(total_registered_quantity, 0)),
    220 2
    221 ) AS demand_to_registered_quantity_ratio,
    222 LAG(total_requested_quantity) OVER (
    223 PARTITION BY equipment_id
    224 ORDER BY quarter_start
    225 ) AS previous_quarter_requested
    226 FROM equipment_demand
    227 WHERE quarter_start IS NOT NULL
    228 )
    229 SELECT
    230 quarter_start,
     283equipment_with_previous_quarter AS (
     284SELECT
     285quarter_start,
     286equipment_id,
    231287equipment_name,
    232288stock_quantity,
     
    238294pending_requested_quantity,
    239295rejected_requested_quantity,
    240 COALESCE(previous_quarter_requested, 0) AS previous_quarter_requested,
    241 total_requested_quantity - COALESCE(previous_quarter_requested, 0) AS requested_quantity_change,
    242 demand_to_registered_quantity_ratio,
     296cancelled_requested_quantity,
     297LAG(total_requested_quantity) OVER (
     298PARTITION BY equipment_id
     299ORDER BY quarter_start
     300) AS previous_quarter_requested_quantity
     301FROM equipment_demand
     302),
     303equipment_ranked AS (
     304SELECT
     305quarter_start,
     306equipment_name,
     307stock_quantity,
     308assigned_room_quantity,
     309total_registered_quantity,
     310reservations_with_equipment,
     311total_requested_quantity,
     312approved_requested_quantity,
     313pending_requested_quantity,
     314rejected_requested_quantity,
     315cancelled_requested_quantity,
     316COALESCE(previous_quarter_requested_quantity, 0) AS previous_quarter_requested_quantity,
     317total_requested_quantity - COALESCE(previous_quarter_requested_quantity, 0) AS request_change_from_previous_quarter,
     318ROUND(
     319total_requested_quantity::numeric / NULLIF(total_registered_quantity, 0),
     3202
     321) AS demand_ratio,
     322DENSE_RANK() OVER (
     323PARTITION BY quarter_start
     324ORDER BY total_requested_quantity DESC, equipment_name
     325) AS demand_rank,
    243326CASE
    244 WHEN demand_to_registered_quantity_ratio >= 1 THEN 'high demand - consider replenishment'
    245 WHEN demand_to_registered_quantity_ratio >= 0.5 THEN 'medium demand'
    246 ELSE 'low demand'
    247 END AS demand_assessment
    248 FROM equipment_analysis
     327WHEN total_requested_quantity > total_registered_quantity THEN 'critical_demand'
     328WHEN total_requested_quantity >= total_registered_quantity * 0.75 THEN 'high_demand'
     329WHEN total_requested_quantity >= total_registered_quantity * 0.40 THEN 'medium_demand'
     330ELSE 'low_demand'
     331END AS demand_level
     332FROM equipment_with_previous_quarter
     333)
     334SELECT
     335quarter_start,
     336equipment_name,
     337stock_quantity,
     338assigned_room_quantity,
     339total_registered_quantity,
     340reservations_with_equipment,
     341total_requested_quantity,
     342approved_requested_quantity,
     343pending_requested_quantity,
     344rejected_requested_quantity,
     345cancelled_requested_quantity,
     346previous_quarter_requested_quantity,
     347request_change_from_previous_quarter,
     348demand_ratio,
     349demand_rank,
     350demand_level
     351FROM equipment_ranked
    249352ORDER BY
    250353quarter_start,
    251 total_requested_quantity DESC,
     354demand_rank,
    252355equipment_name;
    253356}}}
    254357
    255 === Explanation of the SQL solution ===
    256 
    257 The query first calculates the total quantity of each equipment type that is assigned to rooms. This is done in the temporary result ''room_stock'' by grouping records from ''project.room_equipment''.
    258 
    259 The second temporary result, ''equipment_demand'', combines equipment, room stock, requested equipment, and reservations. It calculates the number of reservations that requested each equipment type, the total requested quantity, and the requested quantity by reservation status.
    260 
    261 The third temporary result, ''equipment_analysis'', calculates the demand-to-available-quantity ratio and uses the LAG() window function to compare current quarter demand with previous quarter demand.
    262 
    263 The final SELECT returns the equipment demand analysis and adds a textual demand assessment. If the requested quantity is greater than or equal to the total registered quantity, the report marks the equipment as high demand and suggests replenishment.
    264 
    265 This makes the report analytical because it combines multiple relations, grouping, conditional aggregation, stock comparison, trend comparison, and decision-oriented classification.
    266 
    267358=== Solution Relational Algebra ===
    268359
    269 The following relational algebra expression uses extended relational algebra because the report requires grouping, aggregate functions, and trend comparison.
     360The second report also uses extended relational algebra because it includes grouping, aggregation, left join, derived values, ranking, and comparison with previous quarter demand.
    270361
    271362Let:
    272363
    273 * Equipment = E
    274 * !RoomEquipment = REqRoom
    275 * !ReservationEquipment = REqRes
    276 * Reservations = Res
    277 
    278 First, calculate how much equipment is assigned to rooms:
    279 
    280 {{{
    281 RoomStock =
    282 γ_{equipment_id;
     364* ''E'' = Equipment
     365* ''RE'' = !RoomEquipment
     366* ''REQ'' = !ReservationEquipment
     367* ''RES'' = Reservations
     368
     369First, calculate the quantity of equipment assigned to rooms:
     370
     371{{{
     372RS =
     373γ equipment_id;
    283374SUM(quantity) → assigned_room_quantity
    284 }
    285 (REqRoom)
    286 }}}
    287 
    288 Then join equipment with room stock, requested equipment, and reservations:
    289 
    290 {{{
    291 EquipmentBase =
    292 E ⟕*{E.equipment_id = RoomStock.equipment_id} RoomStock
    293 ⟕*{E.equipment_id = REqRes.equipment_id} REqRes
    294 ⟕_{REqRes.reservation_id = Res.reservation_id} Res
    295 }}}
    296 
    297 Then group the data by quarter and equipment type:
    298 
    299 {{{
    300 EquipmentDemand =
    301 γ_{quarter(reservation_date), E.equipment_id, E.name, E.stock_quantity, assigned_room_quantity;
    302 COUNT(REqRes.reservation_id) → reservations_with_equipment,
     375(RE)
     376}}}
     377
     378Then join reservation equipment with reservations and equipment:
     379
     380{{{
     381A =
     382REQ ⨝ REQ.reservation_id = RES.reservation_id RES
     383}}}
     384
     385{{{
     386B =
     387A ⨝ REQ.equipment_id = E.equipment_id E
     388}}}
     389
     390Then add the equipment quantity assigned to rooms using a left outer join:
     391
     392{{{
     393C =
     394B ⟕ E.equipment_id = RS.equipment_id RS
     395}}}
     396
     397Then select only reservations in the selected year:
     398
     399{{{
     400D =
     401σ reservation_date >= '2026-01-01' AND reservation_date < '2027-01-01'
     402(C)
     403}}}
     404
     405Then group the result by quarter and equipment type:
     406
     407{{{
     408E1 =
     409γ quarter_start, equipment_id, equipment_name, stock_quantity, assigned_room_quantity;
     410COUNT(DISTINCT reservation_id) → reservations_with_equipment,
    303411SUM(requested_quantity) → total_requested_quantity,
    304 SUM_{status = 'approved'}(requested_quantity) → approved_requested_quantity,
    305 SUM_{status = 'pending'}(requested_quantity) → pending_requested_quantity,
    306 SUM_{status = 'rejected'}(requested_quantity) → rejected_requested_quantity
    307 }
    308 (EquipmentBase)
    309 }}}
    310 
    311 Finally, extend the grouped relation with the demand ratio, previous quarter demand, and demand assessment:
     412SUM(requested_quantity WHERE status = 'approved') → approved_requested_quantity,
     413SUM(requested_quantity WHERE status = 'pending') → pending_requested_quantity,
     414SUM(requested_quantity WHERE status = 'rejected') → rejected_requested_quantity,
     415SUM(requested_quantity WHERE status = 'cancelled') → cancelled_requested_quantity
     416(D)
     417}}}
     418
     419Finally, extended relational algebra is used to calculate:
     420
     421* total registered quantity;
     422* demand ratio;
     423* previous quarter demand;
     424* demand change;
     425* demand rank;
     426* demand level classification.
    312427
    313428{{{
    314429Result =
    315 ρ_{total_registered_quantity,
    316 demand_to_registered_quantity_ratio,
    317 previous_quarter_requested,
    318 requested_quantity_change,
    319 demand_assessment}
    320 (EquipmentDemand)
    321 }}}
    322 
    323 The report preserves the meaning of the database model because equipment demand is calculated from !ReservationEquipment, while available equipment is calculated from Equipment and !RoomEquipment.
     430ρ total_registered_quantity, demand_ratio, previous_quarter_requested_quantity,
     431request_change_from_previous_quarter, demand_rank, demand_level
     432(E1)
     433}}}
     434
     435This corresponds to the SQL query where window functions, arithmetic expressions, and CASE expressions are used.
     436
     437=== Report result screenshot ===
     438
     439The following screenshot shows the result of executing the second report in DBeaver.
     440
     441[[Image(report2_equipment_demand.png, width=100%)]]
     442
     443''Figure 2. Quarterly equipment demand report showing requested equipment quantities, registered stock, approved, pending, rejected demand, demand ratio, previous quarter comparison, and demand level assessment.''
     444
     445=== Discussion ===
     446
     447The second report shows how often each equipment type is requested and compares the requested quantity with the equipment registered in the system. This is useful for identifying equipment that is requested more often than expected.
     448
     449For example, if an equipment item has a high demand ratio or a critical demand level, the organization may need to purchase more units, assign more units to rooms, or manage equipment availability more carefully. If an equipment item has low demand, the organization may decide that the existing stock is sufficient.
     450
     451The report also includes a comparison with the previous quarter. This allows administrators to identify whether equipment demand is increasing or decreasing over time.
    324452
    325453== Final discussion ==
    326454
    327 The two implemented reports provide analytical information that is not directly visible from simple table contents.
    328 
    329 The first report focuses on room utilization. It helps identify which rooms are most frequently used and which rooms have the highest number of approved reservation hours. This can help the organization understand room demand and make better decisions about room scheduling and future room allocation.
    330 
    331 The second report focuses on equipment demand. It helps identify which equipment types are frequently requested and whether the current registered quantity is sufficient. This can help the organization decide whether certain equipment should be replenished or redistributed.
    332 
    333 Both reports are implemented with SQL queries over the normalized relational model from Phase P2 and Phase P5. No additional database tables are required because the existing schema already stores the necessary information about rooms, buildings, reservations, users, equipment, equipment assigned to rooms, and equipment requested in reservations.
    334 
    335 The reports can be reused in later phases as part of the application or as administrative database reports.
     455The two reports provide analytical information that is not directly visible from individual reservation records. The first report focuses on room utilization and reservation status, while the second report focuses on equipment demand and stock pressure.
     456
     457The reports are more complex than the basic SQL queries used in previous phases because they use:
     458
     459* multiple joined tables;
     460* common table expressions;
     461* aggregate functions;
     462* conditional aggregation with FILTER;
     463* date-based grouping by quarter;
     464* calculated indicators;
     465* window functions;
     466* ranking;
     467* CASE-based classification.
     468
     469These reports can later be integrated into the prototype or into a future application interface as administrative reports. They support better planning of room capacity, equipment availability, and long-term resource management.