Changes between Version 1 and Version 2 of AdvancedDatabaseDevelopment


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

--

Legend:

Unmodified
Added
Removed
Modified
  • AdvancedDatabaseDevelopment

    v1 v2  
    88
    99[attachment:advanced_database_development.sql advanced_database_development.sql]
     10
     11The following screenshot shows the successful execution of the Phase P7 SQL script in DBeaver.
     12
     13[[Image(p7_script_execution.png, width=100%)]]
    1014
    1115== Data constraints requirements: Prevent overlapping active room reservations ==
     
    6973=== Test example ===
    7074
     75The following insert attempts to create an overlapping reservation for room_id 3 on 2026-03-01 from 09:30 to 10:30.
     76
    7177{{{
    7278INSERT INTO project.reservations (
     
    8894}}}
    8995
    90 If there is already an active reservation for the same room and overlapping time interval, the trigger rejects the insert.
     96If there is already an active reservation for the same room and an overlapping time interval, the trigger rejects the insert.
     97
     98The following screenshot shows that the trigger rejects an overlapping active room reservation.
     99
     100[[Image(p7_room_overlap_trigger_error.png, width=100%)]]
     101
     102=== Discussion ===
     103
     104This rule is implemented at database level, so it protects the database even if a reservation is inserted manually through SQL and not only through the Java prototype application. It is more advanced than the Phase P2 unique constraint because it checks overlapping time intervals, not only identical intervals.
    91105
    92106== Data constraints requirements: Reservation must contain at least one resource ==
     
    100114* both a room and equipment.
    101115
    102 However, a reservation without both a room and requested equipment is invalid. This requirement cannot be enforced by a simple column-level CHECK constraint because the requested equipment is stored in a separate relation, ''project.reservation_equipment''.
    103 
    104 Therefore, a deferred constraint trigger is used. The trigger checks the rule at transaction commit time, after all related rows have been inserted.
     116However, a reservation without both a room and requested equipment is invalid. This requirement cannot be enforced by a simple column-level CHECK constraint because requested equipment is stored in a separate relation, ''project.reservation_equipment''.
     117
     118Therefore, deferred constraint triggers are used. The rule is checked at transaction commit time, after all related rows have been inserted or modified.
    105119
    106120=== Implementation ===
    107121
    108 The trigger function checks whether the reservation has either a room or at least one requested equipment item.
     122The following trigger function checks whether a reservation has either a room or at least one requested equipment item.
    109123
    110124{{{
     
    135149}}}
    136150
    137 The trigger is created as a deferred constraint trigger.
     151The trigger is created as a deferred constraint trigger on the ''project.reservations'' table.
    138152
    139153{{{
     
    146160}}}
    147161
    148 A second deferred trigger checks the same rule when requested equipment records are inserted, updated, or deleted.
     162A second deferred trigger checks the same rule when records in ''project.reservation_equipment'' are inserted, updated, or deleted.
     163
     164{{{
     165CREATE OR REPLACE FUNCTION project.fn_check_reservation_equipment_resource()
     166RETURNS TRIGGER AS $$
     167DECLARE
     168v_reservation_id INTEGER;
     169v_room_id INTEGER;
     170v_has_equipment BOOLEAN;
     171BEGIN
     172v_reservation_id := COALESCE(NEW.reservation_id, OLD.reservation_id);
     173
     174```
     175SELECT room_id
     176INTO v_room_id
     177FROM project.reservations
     178WHERE reservation_id = v_reservation_id;
     179
     180IF NOT FOUND THEN
     181    RETURN COALESCE(NEW, OLD);
     182END IF;
     183
     184SELECT EXISTS (
     185    SELECT 1
     186    FROM project.reservation_equipment re
     187    WHERE re.reservation_id = v_reservation_id
     188)
     189INTO v_has_equipment;
     190
     191IF v_room_id IS NULL AND NOT v_has_equipment THEN
     192    RAISE EXCEPTION
     193        'Reservation % must include at least one resource: either a room or requested equipment.',
     194        v_reservation_id;
     195END IF;
     196
     197RETURN COALESCE(NEW, OLD);
     198```
     199
     200END;
     201$$ LANGUAGE plpgsql;
     202}}}
    149203
    150204{{{
     
    159213=== Discussion ===
    160214
    161 This rule is important because the conceptual model allows flexible reservations, but it does not allow empty reservations. The use of a deferred constraint trigger is appropriate because equipment-only reservations require data in both ''project.reservations'' and ''project.reservation_equipment''.
     215This rule is important because the conceptual model allows flexible reservations, but it does not allow empty reservations. The use of deferred constraint triggers is appropriate because equipment-only reservations require data in both ''project.reservations'' and ''project.reservation_equipment''.
    162216
    163217== Data constraints requirements: Requested equipment stock availability ==
     
    178232=== Implementation ===
    179233
    180 The function ''project.fn_validate_equipment_availability'' checks whether enough equipment is available.
     234The function ''project.fn_validate_equipment_availability'' checks whether enough equipment is available for one reservation.
    181235
    182236{{{
     
    238292}}}
    239293
     294The following trigger function executes the validation when requested equipment is inserted or updated.
     295
     296{{{
     297CREATE OR REPLACE FUNCTION project.fn_trg_validate_equipment_availability()
     298RETURNS TRIGGER AS $$
     299BEGIN
     300PERFORM project.fn_validate_equipment_availability(
     301COALESCE(NEW.reservation_id, OLD.reservation_id)
     302);
     303
     304```
     305RETURN COALESCE(NEW, OLD);
     306```
     307
     308END;
     309$$ LANGUAGE plpgsql;
     310}}}
     311
    240312The validation is executed when requested equipment is inserted or updated, and also when reservation date, time, or status changes.
    241313
     
    246318FOR EACH ROW
    247319EXECUTE FUNCTION project.fn_trg_validate_equipment_availability();
    248 
     320}}}
     321
     322{{{
    249323CREATE TRIGGER trg_validate_equipment_availability_on_reservation
    250324AFTER UPDATE OF reservation_date, start_time, end_time, status
     
    257331=== Discussion ===
    258332
    259 This requirement protects the database from accepting equipment reservations that exceed the available stock during the same period. It is implemented at database level, so the rule is enforced even if the data is inserted outside the prototype application.
     333This requirement protects the database from accepting equipment reservations that exceed the available general stock during the same period. It is implemented at database level, so the rule is enforced even if the data is inserted outside the prototype application.
    260334
    261335== Stored function: Approve or reject reservation ==
     
    364438{{{
    365439SELECT *
    366 FROM project.v_pending_reservation_details;
     440FROM project.v_pending_reservation_details
     441ORDER BY reservation_date, start_time, reservation_id;
    367442}}}
    368443
     
    379454}}}
    380455
     456The following screenshot shows the result returned by the stored function after approving a pending reservation.
     457
     458[[Image(p7_approve_reject_function_result.png, width=100%)]]
     459
    381460After execution, the result can be checked in the base tables:
    382461
     
    391470}}}
    392471
     472The following screenshot shows that the approval record was inserted into the ''project.approvals'' table.
     473
     474[[Image(p7_approval_verification.png, width=100%)]]
     475
     476=== Discussion ===
     477
     478The stored function centralizes the approval operation. Instead of performing separate manual SQL statements for updating the reservation and inserting an approval record, the system can call one function that validates the reservation, validates the approver, updates the reservation status, and inserts the approval decision.
     479
    393480== Trigger: Validate direct approval writes ==
    394481
     
    397484Even if an approval is inserted directly into the ''project.approvals'' table, the database must still check whether the approver has an appropriate role. This prevents invalid approval records from being inserted manually.
    398485
     486Another consistency requirement is that when an approval decision is inserted, the corresponding reservation status should remain synchronized with the approval decision.
     487
    399488=== Implementation ===
    400489
    401 The trigger ''trg_validate_approval_direct_write'' checks the role of the approver before an approval row is inserted or updated.
     490The following trigger function checks the role of the approver before an approval row is inserted or updated.
     491
     492{{{
     493CREATE OR REPLACE FUNCTION project.fn_validate_approval_direct_write()
     494RETURNS TRIGGER AS $$
     495DECLARE
     496v_role VARCHAR(128);
     497BEGIN
     498SELECT role
     499INTO v_role
     500FROM project.users
     501WHERE user_id = NEW.approver_id;
     502
     503```
     504IF NOT FOUND THEN
     505    RAISE EXCEPTION 'Approver user % does not exist.', NEW.approver_id;
     506END IF;
     507
     508IF v_role NOT IN ('admin', 'approver') THEN
     509    RAISE EXCEPTION
     510        'User % cannot approve reservations because role % is not allowed.',
     511        NEW.approver_id,
     512        v_role;
     513END IF;
     514
     515RETURN NEW;
     516```
     517
     518END;
     519$$ LANGUAGE plpgsql;
     520}}}
    402521
    403522{{{
     
    409528}}}
    410529
    411 Another trigger synchronizes the reservation status after an approval is inserted.
     530The following trigger function synchronizes the reservation status after an approval is inserted.
     531
     532{{{
     533CREATE OR REPLACE FUNCTION project.fn_sync_reservation_status_after_approval()
     534RETURNS TRIGGER AS $$
     535BEGIN
     536UPDATE project.reservations
     537SET status = NEW.decision
     538WHERE reservation_id = NEW.reservation_id;
     539
     540```
     541RETURN NEW;
     542```
     543
     544END;
     545$$ LANGUAGE plpgsql;
     546}}}
    412547
    413548{{{
     
    419554}}}
    420555
     556=== Discussion ===
     557
     558These triggers make the approval table safer against manual changes. They also ensure that the reservation status remains consistent with the inserted approval decision.
     559
    421560== Custom domain: Approval decision domain ==
    422561
     
    433572
    434573This custom domain is used as the type of the ''p_decision'' parameter in the stored function ''project.fn_approve_or_reject_reservation''.
     574
     575=== Discussion ===
     576
     577The custom domain improves consistency because the allowed approval decision values are defined once and can be reused in database programming objects.
    435578
    436579== View: Pending reservation details ==
     
    488631ORDER BY reservation_date, start_time, reservation_id;
    489632}}}
     633
     634The following screenshot shows the result of the pending reservation details view.
     635
     636[[Image(p7_pending_reservation_details_view.png, width=100%)]]
     637
     638=== Discussion ===
     639
     640This view is useful for the approval scenario because it gives the approver one readable result instead of requiring manual joins across reservations, users, rooms, buildings, equipment, and reservation equipment.
    490641
    491642== View: Quarterly room utilization ==
     
    581732}}}
    582733
     734The following screenshot shows the result of the quarterly room utilization view.
     735
     736[[Image(p7_quarterly_room_utilization_view.png, width=100%)]]
     737
     738=== Discussion ===
     739
     740This view provides analytical information about room usage. It uses grouping, aggregation, filtering by status, window functions, ranking, and a calculated utilization level. It can support future reports in the application.
     741
    583742== Final discussion ==
    584743
     
    595754* a custom domain is used for approval decisions.
    596755
    597 These additions are more advanced than the basic constraints from Phase P2 because they require triggers, stored functions, cross-table checks, aggregation, and procedural database logic.
     756These additions are more advanced than the basic constraints from Phase P2 because they require triggers, stored functions, cross-table checks, aggregation, window functions, and procedural database logic.
     757
     758The implementation is suitable for the following project phases because it keeps the relational design from Phase P2, while adding stronger consistency rules and reusable database-level functionality.