| 1 | == Индекси |
| 2 | |
| 3 | Индексите ги забрзуваат пребарувањата на често пребарувани колони и странски клучеви. |
| 4 | {{{#!sql |
| 5 | CREATE INDEX idx_user_email ON Hotel_User(email); |
| 6 | CREATE INDEX idx_room_type_available ON Room(room_type, available); |
| 7 | CREATE INDEX idx_reservation_customer ON Reservation(customer_id); |
| 8 | CREATE INDEX idx_payment_reservation ON Payment(reservation_id); |
| 9 | CREATE INDEX idx_service_staff ON Service(staff_id); |
| 10 | }}} |
| 11 | |
| 12 | == Погледи |
| 13 | |
| 14 | === Вкупна цена на резервации |
| 15 | {{{#!sql |
| 16 | CREATE OR REPLACE VIEW reservation_total AS |
| 17 | SELECT r.reservation_id, |
| 18 | (EXTRACT(DAY FROM (r.end_date - r.start_date)) * rm.price_per_night) AS total_cost |
| 19 | FROM Reservation r |
| 20 | JOIN Room rm ON r.room_number = rm.room_number |
| 21 | AND r.building_id = rm.building_id; |
| 22 | }}} |
| 23 | |
| 24 | === Активни резервации по клиент |
| 25 | {{{#!sql |
| 26 | CREATE OR REPLACE VIEW customer_reservations AS |
| 27 | SELECT c.user_id, u.first_name, u.last_name, r.reservation_id, |
| 28 | r.start_date, r.end_date, r.status |
| 29 | FROM Customer c |
| 30 | JOIN Hotel_User u ON u.user_id = c.user_id |
| 31 | JOIN Reservation r ON r.customer_id = c.user_id; |
| 32 | }}} |
| 33 | |
| 34 | === Услуги обезбедени од персоналот |
| 35 | {{{#!sql |
| 36 | CREATE OR REPLACE VIEW staff_services AS |
| 37 | SELECT s.service_id, s.service_type, s.service_date, s.service_status, |
| 38 | st.user_id AS staff_id, u.first_name, u.last_name |
| 39 | FROM Service s |
| 40 | JOIN Staff st ON st.user_id = s.staff_id |
| 41 | JOIN Hotel_User u ON u.user_id = st.user_id; |
| 42 | }}} |
| 43 | |
| 44 | === Преглед за динамичко пресметување на вкупната цена на резервацијата |
| 45 | {{{#!sql |
| 46 | CREATE OR REPLACE VIEW reservation_total AS |
| 47 | SELECT r.reservation_id, |
| 48 | r.start_date, |
| 49 | r.end_date, |
| 50 | rm.price_per_night, |
| 51 | (EXTRACT(DAY FROM (r.end_date - r.start_date)) * rm.price_per_night) AS total_cost |
| 52 | FROM Reservation r |
| 53 | JOIN Room rm ON r.room_number = rm.room_number |
| 54 | AND r.building_id = rm.building_id; |
| 55 | }}} |
| 56 | |
| 57 | == Процедури |
| 58 | |
| 59 | === Креирање резервација |
| 60 | {{{#!sql |
| 61 | CREATE OR REPLACE PROCEDURE make_reservation( |
| 62 | IN p_customer_id BIGINT, |
| 63 | IN p_room_number INT, |
| 64 | IN p_building_id VARCHAR(10), |
| 65 | IN p_start DATE, |
| 66 | IN p_end DATE |
| 67 | ) |
| 68 | LANGUAGE plpgsql |
| 69 | AS $$ |
| 70 | BEGIN |
| 71 | -- Prevent overlapping reservations |
| 72 | IF EXISTS ( |
| 73 | SELECT 1 FROM Reservation |
| 74 | WHERE room_number = p_room_number |
| 75 | AND building_id = p_building_id |
| 76 | AND status = 'Approved' |
| 77 | AND daterange(start_date, end_date, '[]') && daterange(p_start, p_end, '[]') |
| 78 | ) THEN |
| 79 | RAISE EXCEPTION 'Room is already reserved for these dates'; |
| 80 | END IF; |
| 81 | |
| 82 | -- Insert reservation |
| 83 | INSERT INTO Reservation (start_date, end_date, status, room_number, building_id, customer_id) |
| 84 | VALUES (p_start, p_end, 'Pending', p_room_number, p_building_id, p_customer_id); |
| 85 | END; |
| 86 | $$; |
| 87 | }}} |
| 88 | |
| 89 | === Одобри резервација |
| 90 | {{{#!sql |
| 91 | CREATE OR REPLACE PROCEDURE approve_reservation( |
| 92 | IN p_reservation_id BIGINT, |
| 93 | IN p_manager_id BIGINT |
| 94 | ) |
| 95 | LANGUAGE plpgsql |
| 96 | AS $$ |
| 97 | BEGIN |
| 98 | UPDATE Reservation |
| 99 | SET status = 'Approved', |
| 100 | manager_id = p_manager_id |
| 101 | WHERE reservation_id = p_reservation_id; |
| 102 | END; |
| 103 | $$; |
| 104 | }}} |
| 105 | |
| 106 | === Регистрирај плаќање |
| 107 | {{{#!sql |
| 108 | CREATE OR REPLACE PROCEDURE make_payment( |
| 109 | IN p_reservation_id BIGINT, |
| 110 | IN p_method VARCHAR(20) |
| 111 | ) |
| 112 | LANGUAGE plpgsql |
| 113 | AS $$ |
| 114 | BEGIN |
| 115 | INSERT INTO Payment (p_method, reservation_id) |
| 116 | VALUES (p_method, p_reservation_id); |
| 117 | END; |
| 118 | $$; |
| 119 | }}} |
| 120 | |
| 121 | == Функции |
| 122 | |
| 123 | === Ноќи помеѓу датуми |
| 124 | {{{#!sql |
| 125 | CREATE OR REPLACE FUNCTION nights_between(p_start DATE, p_end DATE) |
| 126 | RETURNS INT LANGUAGE sql |
| 127 | AS $$ |
| 128 | SELECT EXTRACT(DAY FROM (p_end - p_start)); |
| 129 | $$; |
| 130 | }}} |
| 131 | |
| 132 | === Пресметка на трошокот за резервација |
| 133 | {{{#!sql |
| 134 | CREATE OR REPLACE FUNCTION reservation_cost(p_reservation_id BIGINT) |
| 135 | RETURNS NUMERIC |
| 136 | LANGUAGE plpgsql |
| 137 | AS $$ |
| 138 | DECLARE |
| 139 | cost NUMERIC; |
| 140 | BEGIN |
| 141 | SELECT (EXTRACT(DAY FROM (r.end_date - r.start_date)) * rm.price_per_night) |
| 142 | INTO cost |
| 143 | FROM Reservation r |
| 144 | JOIN Room rm ON rm.room_number = r.room_number |
| 145 | AND rm.building_id = r.building_id |
| 146 | WHERE r.reservation_id = p_reservation_id; |
| 147 | |
| 148 | RETURN cost; |
| 149 | END; |
| 150 | $$; |
| 151 | }}} |
| 152 | |
| 153 | == Тригери |
| 154 | |
| 155 | === Автоматско ажурирање на достапноста на собата по одобрувањето |
| 156 | {{{#!sql |
| 157 | CREATE OR REPLACE FUNCTION update_room_availability() |
| 158 | RETURNS TRIGGER LANGUAGE plpgsql |
| 159 | AS $$ |
| 160 | BEGIN |
| 161 | IF NEW.status = 'Approved' THEN |
| 162 | UPDATE Room |
| 163 | SET available = FALSE |
| 164 | WHERE room_number = NEW.room_number |
| 165 | AND building_id = NEW.building_id; |
| 166 | ELSIF NEW.status = 'Cancelled' THEN |
| 167 | UPDATE Room |
| 168 | SET available = TRUE |
| 169 | WHERE room_number = NEW.room_number |
| 170 | AND building_id = NEW.building_id; |
| 171 | END IF; |
| 172 | RETURN NEW; |
| 173 | END; |
| 174 | $$; |
| 175 | |
| 176 | CREATE TRIGGER trg_update_room_availability |
| 177 | AFTER UPDATE OF status ON Reservation |
| 178 | FOR EACH ROW |
| 179 | EXECUTE FUNCTION update_room_availability(); |
| 180 | }}} |
| 181 | |
| 182 | === Спречување на бришење корисници со активни резервации |
| 183 | {{{#!sql |
| 184 | CREATE OR REPLACE FUNCTION prevent_user_delete() |
| 185 | RETURNS TRIGGER LANGUAGE plpgsql |
| 186 | AS $$ |
| 187 | BEGIN |
| 188 | IF EXISTS (SELECT 1 FROM Reservation WHERE customer_id = OLD.user_id AND status <> 'Cancelled') THEN |
| 189 | RAISE EXCEPTION 'Cannot delete user with active reservations'; |
| 190 | END IF; |
| 191 | RETURN OLD; |
| 192 | END; |
| 193 | $$; |
| 194 | |
| 195 | CREATE TRIGGER trg_prevent_user_delete |
| 196 | BEFORE DELETE ON Hotel_User |
| 197 | FOR EACH ROW |
| 198 | EXECUTE FUNCTION prevent_user_delete(); |
| 199 | }}} |