| 1 | -- SUPPLIERS (static, 5 suppliers)
|
|---|
| 2 |
|
|---|
| 3 | INSERT INTO Supplier (name, contact_name, phone, email, address) VALUES
|
|---|
| 4 | ('PetCo Supply', 'James Turner', '+12125550101', 'james@petcosupply.com', '12 Commerce St, New York, NY 10001'),
|
|---|
| 5 | ('FurFresh Co', 'Anna Schmidt', '+13105550202', 'anna@furfresh.com', '88 Sunset Blvd, Los Angeles, CA 90028'),
|
|---|
| 6 | ('VetDirect', 'Carlos Reyes', '+13125550303', 'carlos@vetdirect.com', '5 Lake Ave, Chicago, IL 60601'),
|
|---|
| 7 | ('AnimalPlus', 'Sara Novak', '+17135550404', 'sara@animalplus.com', '20 River Rd, Houston, TX 77001'),
|
|---|
| 8 | ('PawMart', 'David Chen', '+16025550505', 'david@pawmart.com', '99 Desert Way, Phoenix, AZ 85001');
|
|---|
| 9 |
|
|---|
| 10 |
|
|---|
| 11 | -- CATEGORIES (static, 5 categories)
|
|---|
| 12 |
|
|---|
| 13 | INSERT INTO Category (name, description) VALUES
|
|---|
| 14 | ('Food', 'Pet food and treats'),
|
|---|
| 15 | ('Toys', 'Toys and entertainment items'),
|
|---|
| 16 | ('Medicine', 'Health and medical supplies'),
|
|---|
| 17 | ('Accessories', 'Collars, leashes and gear'),
|
|---|
| 18 | ('Bedding', 'Beds, mats and sleeping items');
|
|---|
| 19 |
|
|---|
| 20 |
|
|---|
| 21 | -- ROOM TYPES (static, 5 room types)
|
|---|
| 22 |
|
|---|
| 23 | INSERT INTO Room_Type (name, description, price_per_night) VALUES
|
|---|
| 24 | ('Economy', 'Basic room with essentials', 25.00),
|
|---|
| 25 | ('Standard Single', 'Comfortable single-pet room', 45.00),
|
|---|
| 26 | ('Standard Double', 'Room for two pets', 65.00),
|
|---|
| 27 | ('Deluxe Suite', 'Spacious suite with premium amenities', 100.00),
|
|---|
| 28 | ('VIP Penthouse', 'Top-tier suite with luxury comfort', 180.00);
|
|---|
| 29 |
|
|---|
| 30 |
|
|---|
| 31 | -- SERVICES (static, 8 services)
|
|---|
| 32 |
|
|---|
| 33 | INSERT INTO Service (name, description, price, duration_minutes) VALUES
|
|---|
| 34 | ('Grooming', 'Full coat grooming session', 35.00, 60),
|
|---|
| 35 | ('Vet Check', 'Basic health examination', 50.00, 30),
|
|---|
| 36 | ('Training Session', 'One-on-one obedience training', 40.00, 45),
|
|---|
| 37 | ('Daycare', 'Full day supervised care', 30.00, 480),
|
|---|
| 38 | ('Bath & Dry', 'Wash and blow dry', 25.00, 45),
|
|---|
| 39 | ('Nail Trim', 'Nail clipping and filing', 15.00, 20),
|
|---|
| 40 | ('Dental Clean', 'Teeth brushing and cleaning', 20.00, 30),
|
|---|
| 41 | ('Massage', 'Relaxation massage for pets', 30.00, 40);
|
|---|
| 42 |
|
|---|
| 43 |
|
|---|
| 44 | -- HOTELS (static, 10 hotels)
|
|---|
| 45 |
|
|---|
| 46 | INSERT INTO Hotel (name, location) VALUES
|
|---|
| 47 | ('Paw Palace', 'New York'),
|
|---|
| 48 | ('Cozy Paws', 'Los Angeles'),
|
|---|
| 49 | ('Fur Haven', 'Chicago'),
|
|---|
| 50 | ('Happy Tails', 'Houston'),
|
|---|
| 51 | ('PetStay Plus', 'Phoenix'),
|
|---|
| 52 | ('Bark and Relax', 'Seattle'),
|
|---|
| 53 | ('The Woof Inn', 'Miami'),
|
|---|
| 54 | ('Feline Retreat', 'Denver'),
|
|---|
| 55 | ('Pawsome Lodge', 'Boston'),
|
|---|
| 56 | ('Critter Comfort', 'Austin');
|
|---|
| 57 |
|
|---|
| 58 |
|
|---|
| 59 | -- EMPLOYEES (300, ~30 per hotel)
|
|---|
| 60 |
|
|---|
| 61 | INSERT INTO Employee (first_name, last_name, role, phone, email, hire_date, hotel_id)
|
|---|
| 62 | SELECT
|
|---|
| 63 | fn.name,
|
|---|
| 64 | ln.name,
|
|---|
| 65 | (ARRAY['Vet','Groomer','Receptionist','Manager','Caretaker'])[floor(random()*5+1)::int],
|
|---|
| 66 | '+1555' || (1000000000 + floor(random() * 9000000000)::bigint)::text,
|
|---|
| 67 | lower(
|
|---|
| 68 | regexp_replace(fn.name, '[^a-zA-Z0-9]', '', 'g') || '.' ||
|
|---|
| 69 | regexp_replace(ln.name, '[^a-zA-Z0-9]', '', 'g') ||
|
|---|
| 70 | gs || '@' || replace(lower(h.name), ' ', '') || '.com'
|
|---|
| 71 | ),
|
|---|
| 72 | CURRENT_DATE - (random() * 2000)::int,
|
|---|
| 73 | h.hotel_id
|
|---|
| 74 | FROM generate_series(1, 300) gs
|
|---|
| 75 | JOIN (
|
|---|
| 76 | SELECT name, row_number() OVER (ORDER BY random()) AS fn_rn FROM first_names_male
|
|---|
| 77 | UNION ALL
|
|---|
| 78 | SELECT name, row_number() OVER (ORDER BY random()) + (SELECT COUNT(*) FROM first_names_male) FROM first_names_female
|
|---|
| 79 | ) fn ON fn.fn_rn = (gs % ((SELECT COUNT(*) FROM first_names_male) + (SELECT COUNT(*) FROM first_names_female))::int) + 1
|
|---|
| 80 | JOIN (
|
|---|
| 81 | SELECT name, row_number() OVER (ORDER BY random()) AS ln_rn FROM last_names
|
|---|
| 82 | ) ln ON ln.ln_rn = (gs % (SELECT COUNT(*) FROM last_names)::int) + 1
|
|---|
| 83 | JOIN (
|
|---|
| 84 | SELECT hotel_id, name, row_number() OVER (ORDER BY random()) AS h_rn FROM Hotel
|
|---|
| 85 | ) h ON h.h_rn = (gs % (SELECT COUNT(*) FROM Hotel)::int) + 1;
|
|---|
| 86 |
|
|---|
| 87 |
|
|---|
| 88 | -- ROOMS (2,500 total, 250 per hotel)
|
|---|
| 89 |
|
|---|
| 90 | INSERT INTO Room (room_number, capacity, room_type_id, hotel_id)
|
|---|
| 91 | SELECT
|
|---|
| 92 | h.hotel_id || '-' ||
|
|---|
| 93 | CASE
|
|---|
| 94 | WHEN gs <= 83 THEN 'A'
|
|---|
| 95 | WHEN gs <= 166 THEN 'B'
|
|---|
| 96 | ELSE 'C'
|
|---|
| 97 | END || (100 + gs)::text,
|
|---|
| 98 | floor(random() * 3 + 1)::int,
|
|---|
| 99 | ((gs - 1) % (SELECT COUNT(*) FROM Room_Type)::int) + 1,
|
|---|
| 100 | h.hotel_id
|
|---|
| 101 | FROM Hotel h
|
|---|
| 102 | CROSS JOIN generate_series(1, 250) gs;
|
|---|
| 103 |
|
|---|
| 104 |
|
|---|
| 105 | -- CUSTOMERS (150,000)
|
|---|
| 106 |
|
|---|
| 107 | INSERT INTO Customer (first_name, last_name, email, phone, address, registration_date)
|
|---|
| 108 | SELECT
|
|---|
| 109 | fn.name,
|
|---|
| 110 | ln.name,
|
|---|
| 111 | lower(
|
|---|
| 112 | regexp_replace(fn.name, '[^a-zA-Z0-9]', '', 'g') || '.' ||
|
|---|
| 113 | regexp_replace(ln.name, '[^a-zA-Z0-9]', '', 'g') ||
|
|---|
| 114 | gs || '@customer.com'
|
|---|
| 115 | ),
|
|---|
| 116 | '+1555' || (1000000000 + floor(random() * 9000000000)::bigint)::text,
|
|---|
| 117 | a.address,
|
|---|
| 118 | CURRENT_DATE - (random() * 1500)::int
|
|---|
| 119 | FROM generate_series(1, 150000) gs
|
|---|
| 120 | JOIN (
|
|---|
| 121 | SELECT name, row_number() OVER (ORDER BY random()) AS fn_rn FROM first_names_male
|
|---|
| 122 | UNION ALL
|
|---|
| 123 | SELECT name, row_number() OVER (ORDER BY random()) + (SELECT COUNT(*) FROM first_names_male) FROM first_names_female
|
|---|
| 124 | ) fn ON fn.fn_rn = (gs % ((SELECT COUNT(*) FROM first_names_male) + (SELECT COUNT(*) FROM first_names_female))::int) + 1
|
|---|
| 125 | JOIN (
|
|---|
| 126 | SELECT name, row_number() OVER (ORDER BY random()) AS ln_rn FROM last_names
|
|---|
| 127 | ) ln ON ln.ln_rn = (gs % (SELECT COUNT(*) FROM last_names)::int) + 1
|
|---|
| 128 | JOIN (
|
|---|
| 129 | SELECT address, row_number() OVER (ORDER BY random()) AS rn FROM addresses
|
|---|
| 130 | ) a ON a.rn = (gs % (SELECT COUNT(*) FROM addresses)::int) + 1;
|
|---|
| 131 |
|
|---|
| 132 |
|
|---|
| 133 | -- PRODUCTS (500)
|
|---|
| 134 |
|
|---|
| 135 | INSERT INTO Product (name, description, price, category_id, supplier_id)
|
|---|
| 136 | SELECT
|
|---|
| 137 | p.product_name || ' #' || gs,
|
|---|
| 138 | 'Quality pet product - ' || p.product_name,
|
|---|
| 139 | round((random() * 95 + 5)::numeric, 2),
|
|---|
| 140 | (SELECT category_id FROM Category WHERE name = p.category_name),
|
|---|
| 141 | supplier_id
|
|---|
| 142 | FROM generate_series(1, 500) gs
|
|---|
| 143 | JOIN (
|
|---|
| 144 | VALUES
|
|---|
| 145 | ('Premium Kibble', 'Food'),
|
|---|
| 146 | ('Chew Toy', 'Toys'),
|
|---|
| 147 | ('Flea Collar', 'Medicine'),
|
|---|
| 148 | ('Plush Bed', 'Bedding'),
|
|---|
| 149 | ('Catnip', 'Toys'),
|
|---|
| 150 | ('Harness', 'Accessories'),
|
|---|
| 151 | ('Bowl Set', 'Accessories'),
|
|---|
| 152 | ('Vitamin Drops', 'Medicine'),
|
|---|
| 153 | ('Leash', 'Accessories'),
|
|---|
| 154 | ('Shampoo', 'Medicine')
|
|---|
| 155 | ) AS p(product_name, category_name)
|
|---|
| 156 | ON p.product_name = (
|
|---|
| 157 | ARRAY[
|
|---|
| 158 | 'Premium Kibble','Chew Toy','Flea Collar','Plush Bed','Catnip',
|
|---|
| 159 | 'Harness','Bowl Set','Vitamin Drops','Leash','Shampoo'
|
|---|
| 160 | ]
|
|---|
| 161 | )[(gs % 10) + 1]
|
|---|
| 162 | CROSS JOIN LATERAL (
|
|---|
| 163 | SELECT supplier_id
|
|---|
| 164 | FROM Supplier
|
|---|
| 165 | ORDER BY md5(gs::text || 'sup' || random()::text)
|
|---|
| 166 | LIMIT 1
|
|---|
| 167 | ) c2(supplier_id);
|
|---|
| 168 |
|
|---|
| 169 |
|
|---|
| 170 | -- PETS (15,000)
|
|---|
| 171 |
|
|---|
| 172 | INSERT INTO Pet (name, date_of_birth, gender, customer_id, species_id, breed_id)
|
|---|
| 173 | SELECT
|
|---|
| 174 | pet_name,
|
|---|
| 175 | CURRENT_DATE - (random() * 5000)::int,
|
|---|
| 176 | (ARRAY['Male','Female'])[floor(random() * 2 + 1)::int],
|
|---|
| 177 | cust.customer_id,
|
|---|
| 178 | s.species_id,
|
|---|
| 179 | b.breed_id
|
|---|
| 180 | FROM generate_series(15001, 200000) gs
|
|---|
| 181 | CROSS JOIN LATERAL (
|
|---|
| 182 | SELECT val AS pet_name FROM (
|
|---|
| 183 | SELECT val, row_number() OVER (ORDER BY random()) AS rn
|
|---|
| 184 | FROM unnest(ARRAY[
|
|---|
| 185 | 'Buddy','Max','Bella','Lucy','Charlie','Daisy',
|
|---|
| 186 | 'Milo','Luna','Rocky','Coco','Oscar','Lily',
|
|---|
| 187 | 'Teddy','Zoe','Loki','Nala','Bear','Stella',
|
|---|
| 188 | 'Archie','Molly','Bailey','Cooper','Sadie','Duke',
|
|---|
| 189 | 'Rosie','Tucker','Maggie','Zeus','Penny','Bruno'
|
|---|
| 190 | ]::text[]) AS t(val)
|
|---|
| 191 | ) sub WHERE rn = (gs % 30) + 1
|
|---|
| 192 | ) names
|
|---|
| 193 | CROSS JOIN LATERAL (
|
|---|
| 194 | SELECT species_id FROM (
|
|---|
| 195 | SELECT species_id, row_number() OVER (ORDER BY random()) AS rn FROM Species
|
|---|
| 196 | ) sub WHERE rn = (gs % (SELECT COUNT(*) FROM Species)::int) + 1
|
|---|
| 197 | ) s
|
|---|
| 198 | CROSS JOIN LATERAL (
|
|---|
| 199 | SELECT breed_id FROM (
|
|---|
| 200 | SELECT breed_id, row_number() OVER (ORDER BY random()) AS rn
|
|---|
| 201 | FROM Breed WHERE species_id = s.species_id
|
|---|
| 202 | ) sub WHERE rn = (gs % (SELECT COUNT(*) FROM Breed WHERE species_id = s.species_id)::int) + 1
|
|---|
| 203 | ) b
|
|---|
| 204 | CROSS JOIN LATERAL (
|
|---|
| 205 | SELECT customer_id FROM (
|
|---|
| 206 | SELECT customer_id, row_number() OVER (ORDER BY random()) AS rn FROM Customer
|
|---|
| 207 | ) sub WHERE rn = (gs % (SELECT COUNT(*) FROM Customer)::int) + 1
|
|---|
| 208 | ) cust;
|
|---|
| 209 |
|
|---|
| 210 |
|
|---|
| 211 | -- ORDERS (45,000)
|
|---|
| 212 |
|
|---|
| 213 | INSERT INTO "Order" (order_date, status, total_amount, customer_id, hotel_id)
|
|---|
| 214 | SELECT
|
|---|
| 215 | CURRENT_DATE - (random() * 1000)::int,
|
|---|
| 216 | (ARRAY['pending','confirmed','completed','cancelled'])[floor(random() * 4 + 1)::int],
|
|---|
| 217 | round((random() * 500 + 10)::numeric, 2),
|
|---|
| 218 | c.customer_id,
|
|---|
| 219 | h.hotel_id
|
|---|
| 220 | FROM generate_series(1, 45000) gs
|
|---|
| 221 | CROSS JOIN LATERAL (
|
|---|
| 222 | SELECT customer_id FROM (
|
|---|
| 223 | SELECT customer_id, row_number() OVER (ORDER BY random()) AS rn FROM Customer
|
|---|
| 224 | ) sub WHERE rn = (gs % (SELECT COUNT(*) FROM Customer)::int) + 1
|
|---|
| 225 | ) c
|
|---|
| 226 | CROSS JOIN LATERAL (
|
|---|
| 227 | SELECT hotel_id FROM (
|
|---|
| 228 | SELECT hotel_id, row_number() OVER (ORDER BY random()) AS rn FROM Hotel
|
|---|
| 229 | ) sub WHERE rn = (gs % (SELECT COUNT(*) FROM Hotel)::int) + 1
|
|---|
| 230 | ) h;
|
|---|
| 231 |
|
|---|
| 232 |
|
|---|
| 233 | -- ORDER PRODUCTS (~23,000)
|
|---|
| 234 |
|
|---|
| 235 | INSERT INTO OrderProduct (quantity, unit_price, order_id, product_id)
|
|---|
| 236 | SELECT
|
|---|
| 237 | (random() * 9 + 1)::int,
|
|---|
| 238 | (random() * 100 + 1)::numeric(10,2),
|
|---|
| 239 | o.order_id,
|
|---|
| 240 | p.product_id
|
|---|
| 241 | FROM (
|
|---|
| 242 | SELECT order_id, row_number() OVER (ORDER BY random()) AS rn
|
|---|
| 243 | FROM "Order"
|
|---|
| 244 | LIMIT 23000
|
|---|
| 245 | ) o
|
|---|
| 246 | JOIN (
|
|---|
| 247 | SELECT product_id, row_number() OVER (ORDER BY random()) AS rn,
|
|---|
| 248 | COUNT(*) OVER () AS total
|
|---|
| 249 | FROM Product
|
|---|
| 250 | ) p ON p.rn = (
|
|---|
| 251 | ('x' || substr(md5(o.order_id::text || o.rn::text), 1, 8))::bit(32)::int % p.total + 1
|
|---|
| 252 | )
|
|---|
| 253 | ON CONFLICT (order_id, product_id) DO NOTHING;
|
|---|
| 254 |
|
|---|
| 255 |
|
|---|
| 256 | -- RESERVATIONS (7,000,000)
|
|---|
| 257 | -- reservation_date is set to the check-in date (2015–2027)
|
|---|
| 258 | -- so it stays consistent with RoomReservation.check_in_date.
|
|---|
| 259 | DO $$
|
|---|
| 260 | BEGIN
|
|---|
| 261 | FOR iter IN 0..99 LOOP
|
|---|
| 262 | INSERT INTO Reservation (
|
|---|
| 263 | reservation_date,
|
|---|
| 264 | status,
|
|---|
| 265 | notes,
|
|---|
| 266 | total_cost,
|
|---|
| 267 | pet_id,
|
|---|
| 268 | employee_id
|
|---|
| 269 | )
|
|---|
| 270 | WITH
|
|---|
| 271 | pets AS (
|
|---|
| 272 | SELECT
|
|---|
| 273 | pet_id,
|
|---|
| 274 | row_number() OVER (ORDER BY pet_id) - 1 AS rn,
|
|---|
| 275 | count(*) OVER () AS total
|
|---|
| 276 | FROM Pet
|
|---|
| 277 | ),
|
|---|
| 278 | emps AS (
|
|---|
| 279 | SELECT
|
|---|
| 280 | employee_id,
|
|---|
| 281 | row_number() OVER (ORDER BY employee_id) - 1 AS rn,
|
|---|
| 282 | count(*) OVER () AS total
|
|---|
| 283 | FROM Employee
|
|---|
| 284 | ),
|
|---|
| 285 | statuses(idx, val) AS (
|
|---|
| 286 | VALUES
|
|---|
| 287 | (1,'confirmed'),
|
|---|
| 288 | (2,'confirmed'),
|
|---|
| 289 | (3,'confirmed'),
|
|---|
| 290 | (4,'confirmed'),
|
|---|
| 291 | (5,'confirmed'),
|
|---|
| 292 | (6,'confirmed'),
|
|---|
| 293 | (7,'completed'),
|
|---|
| 294 | (8,'completed'),
|
|---|
| 295 | (9,'completed'),
|
|---|
| 296 | (10,'completed'),
|
|---|
| 297 | (11,'pending'),
|
|---|
| 298 | (12,'pending'),
|
|---|
| 299 | (13,'cancelled'),
|
|---|
| 300 | (14,'cancelled'),
|
|---|
| 301 | (15,'no-show')
|
|---|
| 302 | ),
|
|---|
| 303 | notes(idx, val) AS (
|
|---|
| 304 | VALUES
|
|---|
| 305 | (0,'Owner requests daily photo updates.'),
|
|---|
| 306 | (1,'Pet is on a special diet - dry food only.'),
|
|---|
| 307 | (2,'Nervous around loud noises, please keep calm.'),
|
|---|
| 308 | (3,'Very friendly with other animals.'),
|
|---|
| 309 | (4,'Requires medication twice daily.'),
|
|---|
| 310 | (5,NULL),
|
|---|
| 311 | (6,NULL),
|
|---|
| 312 | (7,NULL)
|
|---|
| 313 | )
|
|---|
| 314 | SELECT
|
|---|
| 315 | DATE '2015-01-01'
|
|---|
| 316 | + floor(random() * 4747)::int,
|
|---|
| 317 | s.val,
|
|---|
| 318 | n.val,
|
|---|
| 319 | floor(random() * 800 + 50)::int,
|
|---|
| 320 | p.pet_id,
|
|---|
| 321 | e.employee_id
|
|---|
| 322 | FROM generate_series(1, 100000) gs(n)
|
|---|
| 323 | JOIN statuses s
|
|---|
| 324 | ON s.idx = (gs.n % 15) + 1
|
|---|
| 325 | JOIN notes n
|
|---|
| 326 | ON n.idx = (gs.n * 3 + 5) % 8
|
|---|
| 327 | JOIN pets p
|
|---|
| 328 | ON p.rn = (gs.n * 5 + 2)
|
|---|
| 329 | % (SELECT total FROM pets LIMIT 1)
|
|---|
| 330 | JOIN emps e
|
|---|
| 331 | ON e.rn = (gs.n * 7 + 11)
|
|---|
| 332 | % (SELECT total FROM emps LIMIT 1);
|
|---|
| 333 | END LOOP;
|
|---|
| 334 | END;
|
|---|
| 335 | $$;
|
|---|
| 336 |
|
|---|
| 337 |
|
|---|
| 338 | DROP TABLE RoomReservation;
|
|---|
| 339 |
|
|---|
| 340 | CREATE TABLE RoomReservation (
|
|---|
| 341 | room_reservation_id INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY,
|
|---|
| 342 | check_in_date DATE NOT NULL,
|
|---|
| 343 | check_out_date DATE NOT NULL,
|
|---|
| 344 | reservation_id INTEGER NOT NULL,
|
|---|
| 345 | room_id INTEGER NOT NULL,
|
|---|
| 346 | PRIMARY KEY (room_reservation_id),
|
|---|
| 347 | CONSTRAINT uq_roomreservation_reservation
|
|---|
| 348 | UNIQUE (reservation_id),
|
|---|
| 349 | CONSTRAINT chk_roomres_dates
|
|---|
| 350 | CHECK (check_out_date > check_in_date),
|
|---|
| 351 | CONSTRAINT no_overlapping_room_reservations
|
|---|
| 352 | EXCLUDE USING GIST (
|
|---|
| 353 | room_id WITH =,
|
|---|
| 354 | daterange(check_in_date, check_out_date, '[)') WITH &&
|
|---|
| 355 | ),
|
|---|
| 356 | CONSTRAINT fk_roomres_room
|
|---|
| 357 | FOREIGN KEY (room_id) REFERENCES Room(room_id)
|
|---|
| 358 | ON DELETE RESTRICT ON UPDATE CASCADE,
|
|---|
| 359 | CONSTRAINT fk_roomres_reservation
|
|---|
| 360 | FOREIGN KEY (reservation_id) REFERENCES Reservation(reservation_id)
|
|---|
| 361 | ON DELETE CASCADE ON UPDATE CASCADE
|
|---|
| 362 | );
|
|---|
| 363 |
|
|---|
| 364 | -- Step 2: Insert
|
|---|
| 365 | DO $$
|
|---|
| 366 | BEGIN
|
|---|
| 367 | FOR iter IN 0..99 LOOP
|
|---|
| 368 | INSERT INTO RoomReservation (
|
|---|
| 369 | check_in_date,
|
|---|
| 370 | check_out_date,
|
|---|
| 371 | reservation_id,
|
|---|
| 372 | room_id
|
|---|
| 373 | )
|
|---|
| 374 | WITH rooms AS (
|
|---|
| 375 | SELECT
|
|---|
| 376 | room_id,
|
|---|
| 377 | (row_number() OVER (ORDER BY room_id) - 1)::int AS room_index,
|
|---|
| 378 | count(*) OVER ()::int AS total_rooms
|
|---|
| 379 | FROM Room
|
|---|
| 380 | ),
|
|---|
| 381 | reservations AS (
|
|---|
| 382 | SELECT
|
|---|
| 383 | reservation_id,
|
|---|
| 384 | reservation_date,
|
|---|
| 385 | (iter * 100000) + (row_number() OVER (ORDER BY reservation_id) - 1)::int AS global_index
|
|---|
| 386 | FROM (
|
|---|
| 387 | SELECT reservation_id, reservation_date
|
|---|
| 388 | FROM Reservation
|
|---|
| 389 | ORDER BY reservation_id
|
|---|
| 390 | LIMIT 100000
|
|---|
| 391 | OFFSET (iter * 100000)
|
|---|
| 392 | ) x
|
|---|
| 393 | ),
|
|---|
| 394 | assigned AS (
|
|---|
| 395 | SELECT
|
|---|
| 396 | r.reservation_id,
|
|---|
| 397 | r.reservation_date,
|
|---|
| 398 | rm.room_id,
|
|---|
| 399 | rm.total_rooms,
|
|---|
| 400 | r.global_index,
|
|---|
| 401 | floor(random() * 6 + 1)::int AS stay_length
|
|---|
| 402 | FROM reservations r
|
|---|
| 403 | JOIN rooms rm
|
|---|
| 404 | ON rm.room_index = r.global_index % rm.total_rooms
|
|---|
| 405 | ),
|
|---|
| 406 | scheduled AS (
|
|---|
| 407 | SELECT
|
|---|
| 408 | reservation_id,
|
|---|
| 409 | room_id,
|
|---|
| 410 | DATE '2015-01-01'
|
|---|
| 411 | + ((global_index / total_rooms) * 8)::int AS check_in_date,
|
|---|
| 412 | DATE '2015-01-01'
|
|---|
| 413 | + ((global_index / total_rooms) * 8)::int
|
|---|
| 414 | + stay_length AS check_out_date
|
|---|
| 415 | FROM assigned
|
|---|
| 416 | )
|
|---|
| 417 | SELECT
|
|---|
| 418 | check_in_date,
|
|---|
| 419 | check_out_date,
|
|---|
| 420 | reservation_id,
|
|---|
| 421 | room_id
|
|---|
| 422 | FROM scheduled
|
|---|
| 423 | ORDER BY room_id, check_in_date
|
|---|
| 424 | ON CONFLICT (reservation_id) DO NOTHING;
|
|---|
| 425 |
|
|---|
| 426 | RAISE NOTICE 'Completed iteration % of 99 (offset %)', iter, iter * 100000;
|
|---|
| 427 | END LOOP;
|
|---|
| 428 | END;
|
|---|
| 429 | $$;
|
|---|
| 430 |
|
|---|
| 431 | -- Step 3: Verify
|
|---|
| 432 | SELECT COUNT(*) FROM RoomReservation; -- should be ~10,000,000
|
|---|
| 433 |
|
|---|
| 434 |
|
|---|
| 435 |
|
|---|
| 436 |
|
|---|
| 437 |
|
|---|
| 438 | SET work_mem = '512MB';
|
|---|
| 439 | SET synchronous_commit = OFF;
|
|---|
| 440 |
|
|---|
| 441 | DO $$
|
|---|
| 442 | BEGIN
|
|---|
| 443 | FOR iter IN 0..99 LOOP
|
|---|
| 444 | INSERT INTO RoomReservation (
|
|---|
| 445 | check_in_date,
|
|---|
| 446 | check_out_date,
|
|---|
| 447 | reservation_id,
|
|---|
| 448 | room_id
|
|---|
| 449 | )
|
|---|
| 450 | WITH rooms AS (
|
|---|
| 451 | SELECT
|
|---|
| 452 | room_id,
|
|---|
| 453 | (row_number() OVER (ORDER BY room_id) - 1)::int AS room_index,
|
|---|
| 454 | count(*) OVER ()::int AS total_rooms
|
|---|
| 455 | FROM Room
|
|---|
| 456 | ),
|
|---|
| 457 | reservations AS (
|
|---|
| 458 | SELECT
|
|---|
| 459 | reservation_id,
|
|---|
| 460 | reservation_date,
|
|---|
| 461 | (row_number() OVER (ORDER BY reservation_id) - 1)::int AS res_index
|
|---|
| 462 | FROM (
|
|---|
| 463 | SELECT reservation_id, reservation_date
|
|---|
| 464 | FROM Reservation
|
|---|
| 465 | ORDER BY reservation_id
|
|---|
| 466 | LIMIT 100000
|
|---|
| 467 | OFFSET (iter * 100000)
|
|---|
| 468 | ) x
|
|---|
| 469 | ),
|
|---|
| 470 | assigned AS (
|
|---|
| 471 | SELECT
|
|---|
| 472 | r.reservation_id,
|
|---|
| 473 | r.reservation_date,
|
|---|
| 474 | rm.room_id,
|
|---|
| 475 | floor(random() * 6 + 1)::int AS stay_length
|
|---|
| 476 | FROM reservations r
|
|---|
| 477 | JOIN rooms rm
|
|---|
| 478 | ON rm.room_index = r.res_index % rm.total_rooms
|
|---|
| 479 | ),
|
|---|
| 480 | scheduled AS (
|
|---|
| 481 | SELECT
|
|---|
| 482 | reservation_id,
|
|---|
| 483 | room_id,
|
|---|
| 484 | reservation_date AS check_in_date,
|
|---|
| 485 | reservation_date + stay_length AS check_out_date
|
|---|
| 486 | FROM assigned
|
|---|
| 487 | )
|
|---|
| 488 | SELECT
|
|---|
| 489 | check_in_date,
|
|---|
| 490 | check_out_date,
|
|---|
| 491 | reservation_id,
|
|---|
| 492 | room_id
|
|---|
| 493 | FROM scheduled
|
|---|
| 494 | ON CONFLICT (reservation_id) DO NOTHING;
|
|---|
| 495 |
|
|---|
| 496 | RAISE NOTICE 'Completed iteration % of 99 (offset %)', iter, iter * 100000;
|
|---|
| 497 | END LOOP;
|
|---|
| 498 | END;
|
|---|
| 499 | $$;
|
|---|
| 500 |
|
|---|
| 501 | -- Step 7: Reset settings
|
|---|
| 502 | SET synchronous_commit = ON;
|
|---|
| 503 | SET work_mem = '4MB';
|
|---|
| 504 |
|
|---|
| 505 | -- Reset settings
|
|---|
| 506 | SET synchronous_commit = ON;
|
|---|
| 507 | SET work_mem = '4MB';
|
|---|
| 508 |
|
|---|
| 509 | -- Verify
|
|---|
| 510 | SELECT COUNT(*) FROM Date;
|
|---|
| 511 |
|
|---|
| 512 | -- SERVICE RESERVATIONS
|
|---|
| 513 | -- ~60 % of RoomReservations get at least one service.
|
|---|
| 514 | -- Each selected reservation gets 1–3 services at random,
|
|---|
| 515 | -- scheduled on a random day within the actual room stay.
|
|---|
| 516 | WITH reservation_sample AS (
|
|---|
| 517 | SELECT
|
|---|
| 518 | rr.reservation_id,
|
|---|
| 519 | rr.check_in_date,
|
|---|
| 520 | rr.check_out_date,
|
|---|
| 521 | -- Assign number of services: 0, 1, 2, or 3
|
|---|
| 522 | -- 40% = 0, 35% = 1, 18% = 2, 7% = 3
|
|---|
| 523 | CASE
|
|---|
| 524 | WHEN random() < 0.40 THEN 0
|
|---|
| 525 | WHEN random() < 0.58 THEN 1 -- 35% of remaining
|
|---|
| 526 | WHEN random() < 0.75 THEN 2 -- 18% of remaining
|
|---|
| 527 | ELSE 3
|
|---|
| 528 | END AS num_services
|
|---|
| 529 | FROM RoomReservation rr
|
|---|
| 530 | WHERE rr.check_out_date > rr.check_in_date
|
|---|
| 531 | ),
|
|---|
| 532 | expanded AS (
|
|---|
| 533 | SELECT
|
|---|
| 534 | rs.reservation_id,
|
|---|
| 535 | rs.check_in_date,
|
|---|
| 536 | rs.check_out_date,
|
|---|
| 537 | gs.service_num
|
|---|
| 538 | FROM reservation_sample rs
|
|---|
| 539 | CROSS JOIN generate_series(1, rs.num_services) gs(service_num)
|
|---|
| 540 | WHERE rs.num_services > 0
|
|---|
| 541 | ),
|
|---|
| 542 | services_numbered AS (
|
|---|
| 543 | SELECT
|
|---|
| 544 | service_id,
|
|---|
| 545 | row_number() OVER (ORDER BY service_id) - 1 AS svc_index,
|
|---|
| 546 | count(*) OVER () AS total_services
|
|---|
| 547 | FROM Service
|
|---|
| 548 | )
|
|---|
| 549 | INSERT INTO ServiceReservation (
|
|---|
| 550 | scheduled_date,
|
|---|
| 551 | scheduled_time,
|
|---|
| 552 | status,
|
|---|
| 553 | reservation_id,
|
|---|
| 554 | service_id
|
|---|
| 555 | )
|
|---|
| 556 | SELECT
|
|---|
| 557 | e.check_in_date
|
|---|
| 558 | + floor(random() * GREATEST(e.check_out_date - e.check_in_date, 1))::int
|
|---|
| 559 | AS scheduled_date,
|
|---|
| 560 | (ARRAY[
|
|---|
| 561 | '09:00','10:00','11:00','12:00','13:00',
|
|---|
| 562 | '14:00','15:00','16:00','17:00'
|
|---|
| 563 | ])[floor(random() * 9 + 1)::int]::time AS scheduled_time,
|
|---|
| 564 | (ARRAY['scheduled','completed','cancelled','no-show'])[floor(random()*4 + 1)::int],
|
|---|
| 565 | e.reservation_id,
|
|---|
| 566 | s.service_id
|
|---|
| 567 | FROM expanded e
|
|---|
| 568 | JOIN services_numbered s
|
|---|
| 569 | ON s.svc_index = (e.reservation_id * e.service_num * 7 + e.service_num * 13)
|
|---|
| 570 | % (SELECT total_services FROM services_numbered LIMIT 1)
|
|---|
| 571 | ON CONFLICT DO NOTHING;
|
|---|
| 572 |
|
|---|
| 573 | -- EMPLOYEE–SERVICE (up to 240 unique pairs)
|
|---|
| 574 |
|
|---|
| 575 | INSERT INTO Employee_Service (employee_id, service_id)
|
|---|
| 576 | SELECT DISTINCT e.employee_id, s.service_id
|
|---|
| 577 | FROM generate_series(1, 1000) gs
|
|---|
| 578 | JOIN (SELECT employee_id, row_number() OVER (ORDER BY random()) AS rn FROM Employee) e
|
|---|
| 579 | ON e.rn = (gs % (SELECT COUNT(*) FROM Employee)::int) + 1
|
|---|
| 580 | JOIN (SELECT service_id, row_number() OVER (ORDER BY random()) AS rn FROM Service) s
|
|---|
| 581 | ON s.rn = (gs % (SELECT COUNT(*) FROM Service)::int) + 1
|
|---|
| 582 | ON CONFLICT DO NOTHING;
|
|---|
| 583 |
|
|---|
| 584 |
|
|---|
| 585 | -- PRODUCT–SERVICE (up to 120 unique pairs)
|
|---|
| 586 |
|
|---|
| 587 | INSERT INTO Product_Service (product_id, service_id)
|
|---|
| 588 | SELECT DISTINCT p.product_id, s.service_id
|
|---|
| 589 | FROM generate_series(1, 400) gs
|
|---|
| 590 | JOIN (SELECT product_id, row_number() OVER (ORDER BY random()) AS rn FROM Product) p
|
|---|
| 591 | ON p.rn = (gs % (SELECT COUNT(*) FROM Product)::int) + 1
|
|---|
| 592 | JOIN (SELECT service_id, row_number() OVER (ORDER BY random()) AS rn FROM Service) s
|
|---|
| 593 | ON s.rn = (gs % (SELECT COUNT(*) FROM Service)::int) + 1
|
|---|
| 594 | ON CONFLICT DO NOTHING;
|
|---|
| 595 |
|
|---|
| 596 |
|
|---|
| 597 | -- REVIEWS (150,000)
|
|---|
| 598 |
|
|---|
| 599 | INSERT INTO Review (review_date, rating, comment, customer_id, hotel_id)
|
|---|
| 600 | SELECT
|
|---|
| 601 | CURRENT_DATE - (random() * 365)::int,
|
|---|
| 602 | rating,
|
|---|
| 603 | CASE
|
|---|
| 604 | WHEN rating >= 9 THEN (ARRAY[
|
|---|
| 605 | 'Absolutely incredible experience — our dog was treated like royalty!',
|
|---|
| 606 | 'Best pet hotel we have ever used. The staff went above and beyond.',
|
|---|
| 607 | 'Our cat came home happy, clean, and clearly well-loved. 10 out of 10!',
|
|---|
| 608 | 'Exceptional service from check-in to check-out. Will never go anywhere else.',
|
|---|
| 609 | 'The VIP suite was worth every penny. Our pup was in heaven!',
|
|---|
| 610 | 'Flawless experience. Staff remembered our pet by name on the second visit.',
|
|---|
| 611 | 'I was nervous leaving my rabbit for the first time, but the team was amazing.',
|
|---|
| 612 | 'Five stars is not enough. Truly the gold standard of pet care.',
|
|---|
| 613 | 'Our senior dog received such gentle and attentive care. We are so grateful.',
|
|---|
| 614 | 'Immaculate facilities, caring staff, and our pets came home thriving.'
|
|---|
| 615 | ])[floor(random() * 10 + 1)::int]
|
|---|
| 616 |
|
|---|
| 617 | WHEN rating >= 7 THEN (ARRAY[
|
|---|
| 618 | 'Really great stay overall. The staff were friendly and clearly love animals.',
|
|---|
| 619 | 'Our dog seemed very happy when we picked him up. Clean rooms, good service.',
|
|---|
| 620 | 'Solid experience. Would definitely recommend to other pet owners.',
|
|---|
| 621 | 'Great grooming service included — our cat looked fabulous afterwards.',
|
|---|
| 622 | 'Very professional team. Our pet was well cared for throughout the stay.',
|
|---|
| 623 | 'Good facilities and attentive staff. Only minor issue was parking.',
|
|---|
| 624 | 'Our pets had a wonderful time. The play area is a great touch.',
|
|---|
| 625 | 'Really impressed with the daily photo updates. Gave us great peace of mind.',
|
|---|
| 626 | 'Friendly reception, clean rooms, and our dog ate well the whole time.',
|
|---|
| 627 | 'Above average in every way. We have already booked our next stay.'
|
|---|
| 628 | ])[floor(random() * 10 + 1)::int]
|
|---|
| 629 |
|
|---|
| 630 | WHEN rating >= 5 THEN (ARRAY[
|
|---|
| 631 | 'Decent place overall. Nothing spectacular but the pets were looked after.',
|
|---|
| 632 | 'Average experience. Staff were polite but not particularly attentive.',
|
|---|
| 633 | 'Rooms were clean enough. Our dog seemed fine but not especially happy.',
|
|---|
| 634 | 'It does the job. Would consider returning if prices stay reasonable.',
|
|---|
| 635 | 'Fairly standard pet hotel. No complaints but no real highlights either.',
|
|---|
| 636 | 'Middle of the road. Communication could be better but the care was okay.',
|
|---|
| 637 | 'Our cat was safe and fed, which is what matters. Facilities felt a bit dated.',
|
|---|
| 638 | 'Okay for the price. Do not expect luxury but basics are covered.',
|
|---|
| 639 | 'Mixed feelings. Some staff were great, others less engaged.',
|
|---|
| 640 | 'Not bad, not great. We might try somewhere else next time just to compare.'
|
|---|
| 641 | ])[floor(random() * 10 + 1)::int]
|
|---|
| 642 |
|
|---|
| 643 | WHEN rating >= 3 THEN (ARRAY[
|
|---|
| 644 | 'Disappointing visit. Our dog seemed stressed when we picked him up.',
|
|---|
| 645 | 'Rooms were smaller than advertised and not very clean.',
|
|---|
| 646 | 'Staff seemed overwhelmed and communication was poor throughout.',
|
|---|
| 647 | 'Expected much more for the price. Facilities felt neglected.',
|
|---|
| 648 | 'Our pet came home with a minor scratch — no explanation was given.',
|
|---|
| 649 | 'Booking was easy but the actual experience did not match the website.',
|
|---|
| 650 | 'Not enough staff on duty. Our pet did not get the attention promised.',
|
|---|
| 651 | 'Unimpressive. The grooming service was rushed and below standard.',
|
|---|
| 652 | 'Several issues during the stay that were not handled well by management.',
|
|---|
| 653 | 'Would not rush back. There are better options in the area for less money.'
|
|---|
| 654 | ])[floor(random() * 10 + 1)::int]
|
|---|
| 655 |
|
|---|
| 656 | ELSE (ARRAY[
|
|---|
| 657 | 'Terrible experience. Our pet came home visibly distressed.',
|
|---|
| 658 | 'Absolutely awful. Filthy rooms, rude staff, zero accountability.',
|
|---|
| 659 | 'I would not leave a goldfish here. Deeply disappointed and angry.',
|
|---|
| 660 | 'Our dog lost weight during the stay. Clear sign of neglect.',
|
|---|
| 661 | 'Staff were dismissive when we raised concerns. Totally unacceptable.',
|
|---|
| 662 | 'The worst pet hotel we have ever used. Avoid at all costs.',
|
|---|
| 663 | 'Disgusting conditions. Reported to local animal welfare authorities.',
|
|---|
| 664 | 'No care, no communication, no apology. A complete waste of money.',
|
|---|
| 665 | 'Our cat was returned to us dehydrated. Shocking level of negligence.',
|
|---|
| 666 | 'One star is too generous. This place should not be operating.'
|
|---|
| 667 | ])[floor(random() * 10 + 1)::int]
|
|---|
| 668 | END,
|
|---|
| 669 | c.customer_id,
|
|---|
| 670 | h.hotel_id
|
|---|
| 671 | FROM (
|
|---|
| 672 | SELECT
|
|---|
| 673 | gs,
|
|---|
| 674 | floor(random() * 10 + 1)::int AS rating
|
|---|
| 675 | FROM generate_series(1, 150000) gs
|
|---|
| 676 | ) rated
|
|---|
| 677 | CROSS JOIN LATERAL (
|
|---|
| 678 | SELECT customer_id FROM (
|
|---|
| 679 | SELECT customer_id, row_number() OVER (ORDER BY random()) AS rn FROM Customer
|
|---|
| 680 | ) sub WHERE rn = (rated.gs % (SELECT COUNT(*) FROM Customer)::int) + 1
|
|---|
| 681 | ) c
|
|---|
| 682 | CROSS JOIN LATERAL (
|
|---|
| 683 | SELECT hotel_id FROM (
|
|---|
| 684 | SELECT hotel_id, row_number() OVER (ORDER BY random()) AS rn FROM Hotel
|
|---|
| 685 | ) sub WHERE rn = (rated.gs % (SELECT COUNT(*) FROM Hotel)::int) + 1
|
|---|
| 686 | ) h;
|
|---|
| 687 |
|
|---|
| 688 |
|
|---|
| 689 | -- MEDICAL RECORDS (300,000)
|
|---|
| 690 |
|
|---|
| 691 | INSERT INTO MedicalRecord (record_date, status, vet_name, alergies, medications, note, diagnosis, pet_id)
|
|---|
| 692 | SELECT
|
|---|
| 693 | CURRENT_DATE - (random() * 730)::int,
|
|---|
| 694 | (ARRAY['healthy','healthy','sick','recovering'])[floor(random() * 4 + 1)::int],
|
|---|
| 695 | 'Dr. ' || ln.name,
|
|---|
| 696 | (ARRAY[NULL, 'Pollen', 'Dust mites', 'Certain proteins', 'Flea bites'])[floor(random() * 5 + 1)::int],
|
|---|
| 697 | (ARRAY[NULL, 'Antibiotic', 'Anti-inflammatory', 'Antiparasitic', 'Vitamin supplement'])[floor(random() * 5 + 1)::int],
|
|---|
| 698 | (ARRAY[NULL, 'Monitor weight weekly.', 'Avoid stressful environments.', 'Follow-up in 2 weeks.'])[floor(random() * 4 + 1)::int],
|
|---|
| 699 | (ARRAY['Routine checkup', 'Mild infection', 'Skin irritation', 'Dental issue', 'Ear infection', 'Overweight'])[floor(random() * 6 + 1)::int],
|
|---|
| 700 | pet.pet_id
|
|---|
| 701 | FROM generate_series(1, 300000) gs
|
|---|
| 702 | JOIN (
|
|---|
| 703 | SELECT name, row_number() OVER (ORDER BY random()) AS ln_rn FROM last_names
|
|---|
| 704 | ) ln ON ln.ln_rn = (gs % (SELECT COUNT(*) FROM last_names)::int) + 1
|
|---|
| 705 | JOIN (
|
|---|
| 706 | SELECT pet_id, row_number() OVER (ORDER BY random()) AS rn FROM Pet
|
|---|
| 707 | ) pet ON pet.rn = (gs % (SELECT COUNT(*) FROM Pet)::int) + 1;
|
|---|
| 708 |
|
|---|
| 709 |
|
|---|
| 710 | -- PET DELIVERIES (80,000)
|
|---|
| 711 |
|
|---|
| 712 | INSERT INTO PetDelivery (delivery_time, status, destination, reservation_id, employee_id)
|
|---|
| 713 | SELECT
|
|---|
| 714 | NOW() - (random() * 365 * INTERVAL '1 day'),
|
|---|
| 715 | st.val,
|
|---|
| 716 | dest.val,
|
|---|
| 717 | r.reservation_id,
|
|---|
| 718 | e.employee_id
|
|---|
| 719 | FROM (
|
|---|
| 720 | SELECT reservation_id, row_number() OVER (ORDER BY random()) AS rn
|
|---|
| 721 | FROM Reservation
|
|---|
| 722 | LIMIT 80000
|
|---|
| 723 | ) r
|
|---|
| 724 | CROSS JOIN LATERAL (
|
|---|
| 725 | SELECT val FROM (
|
|---|
| 726 | SELECT val, row_number() OVER (ORDER BY random()) AS rn
|
|---|
| 727 | FROM unnest(ARRAY['scheduled','delivered','failed','confirmed']::text[]) AS t(val)
|
|---|
| 728 | ) sub WHERE rn = (r.rn % 4) + 1
|
|---|
| 729 | ) st
|
|---|
| 730 | CROSS JOIN LATERAL (
|
|---|
| 731 | SELECT val FROM (
|
|---|
| 732 | SELECT val, row_number() OVER (ORDER BY random()) AS rn
|
|---|
| 733 | FROM unnest(ARRAY['home','hotel','vet clinic','airport']::text[]) AS t(val)
|
|---|
| 734 | ) sub WHERE rn = (r.rn % 4) + 1
|
|---|
| 735 | ) dest
|
|---|
| 736 | CROSS JOIN LATERAL (
|
|---|
| 737 | SELECT employee_id FROM (
|
|---|
| 738 | SELECT employee_id, row_number() OVER (ORDER BY random()) AS rn FROM Employee
|
|---|
| 739 | ) sub WHERE rn = (r.rn % (SELECT COUNT(*) FROM Employee)::int) + 1
|
|---|
| 740 | ) e;
|
|---|
| 741 |
|
|---|
| 742 |
|
|---|
| 743 | -- PAYMENTS (~30,000)
|
|---|
| 744 |
|
|---|
| 745 | SET work_mem = '512MB';
|
|---|
| 746 | SET synchronous_commit = OFF;
|
|---|
| 747 |
|
|---|
| 748 | DO $$
|
|---|
| 749 | BEGIN
|
|---|
| 750 | FOR iter IN 0..99 LOOP
|
|---|
| 751 | INSERT INTO Payment (payment_date, amount, payment_method, status, reservation_id)
|
|---|
| 752 | SELECT
|
|---|
| 753 | r.reservation_date + floor(random() * 3)::int,
|
|---|
| 754 | r.total_cost,
|
|---|
| 755 | (ARRAY['credit card','debit card','cash','bank transfer','PayPal'])[floor(random() * 5 + 1)::int],
|
|---|
| 756 | (ARRAY['completed','completed','completed','completed','refunded','pending'])[floor(random() * 6 + 1)::int],
|
|---|
| 757 | r.reservation_id
|
|---|
| 758 | FROM (
|
|---|
| 759 | SELECT reservation_id, reservation_date, total_cost
|
|---|
| 760 | FROM Reservation
|
|---|
| 761 | WHERE status IN ('confirmed', 'completed')
|
|---|
| 762 | ORDER BY reservation_id
|
|---|
| 763 | LIMIT 100000
|
|---|
| 764 | OFFSET (iter * 100000)
|
|---|
| 765 | ) r;
|
|---|
| 766 |
|
|---|
| 767 | RAISE NOTICE 'Completed iteration % of 99 (offset %)', iter, iter * 100000;
|
|---|
| 768 | END LOOP;
|
|---|
| 769 | END;
|
|---|
| 770 | $$;
|
|---|
| 771 |
|
|---|
| 772 | SET synchronous_commit = ON;
|
|---|
| 773 | SET work_mem = '4MB';
|
|---|
| 774 |
|
|---|
| 775 | -- Verify
|
|---|
| 776 | SELECT COUNT(*) FROM Payment;
|
|---|
| 777 |
|
|---|
| 778 | -- DELIVERIES (¬23,000)
|
|---|
| 779 |
|
|---|
| 780 | INSERT INTO Delivery (delivered_at, status, hotel_id, purchase_id)
|
|---|
| 781 | SELECT
|
|---|
| 782 | (ARRAY['morning','afternoon','evening','overnight'])[floor(random() * 4 + 1)::int],
|
|---|
| 783 | (ARRAY['pending','in_transit','delivered','failed'])[floor(random() * 4 + 1)::int],
|
|---|
| 784 | o.hotel_id,
|
|---|
| 785 | op.orderproduct_id
|
|---|
| 786 | FROM OrderProduct op
|
|---|
| 787 | JOIN "Order" o ON o.order_id = op.order_id;
|
|---|
| 788 |
|
|---|
| 789 |
|
|---|
| 790 | -- VIEW: v_room_availability
|
|---|
| 791 |
|
|---|
| 792 | CREATE OR REPLACE VIEW v_room_availability AS
|
|---|
| 793 | SELECT
|
|---|
| 794 | h.hotel_id,
|
|---|
| 795 | h.name AS hotel_name,
|
|---|
| 796 | h.location,
|
|---|
| 797 | r.room_id,
|
|---|
| 798 | r.room_number,
|
|---|
| 799 | r.capacity,
|
|---|
| 800 | rt.name AS room_type,
|
|---|
| 801 | rt.price_per_night,
|
|---|
| 802 | d.date,
|
|---|
| 803 | d.status AS availability_status,
|
|---|
| 804 | CASE WHEN d.status = 'occupied' THEN TRUE ELSE FALSE END AS is_occupied,
|
|---|
| 805 | CASE WHEN d.status = 'available' THEN TRUE ELSE FALSE END AS is_available,
|
|---|
| 806 | CASE WHEN d.status = 'maintenance' THEN TRUE ELSE FALSE END AS in_maintenance
|
|---|
| 807 | FROM Room r
|
|---|
| 808 | JOIN Hotel h ON h.hotel_id = r.hotel_id
|
|---|
| 809 | JOIN Room_Type rt ON rt.room_type_id = r.room_type_id
|
|---|
| 810 | LEFT JOIN Date d ON d.room_id = r.room_id;
|
|---|
| 811 |
|
|---|
| 812 |
|
|---|
| 813 |
|
|---|
| 814 |
|
|---|
| 815 |
|
|---|
| 816 |
|
|---|
| 817 | -- TOCNITE ROOM RESERVATION I DATE INSERTS
|
|---|
| 818 |
|
|---|
| 819 |
|
|---|
| 820 |
|
|---|
| 821 |
|
|---|
| 822 | -- Step 2: Recreate RoomReservation without exclusion constraint
|
|---|
| 823 | CREATE TABLE RoomReservation (
|
|---|
| 824 | room_reservation_id INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY,
|
|---|
| 825 | check_in_date DATE NOT NULL,
|
|---|
| 826 | check_out_date DATE NOT NULL,
|
|---|
| 827 | reservation_id INTEGER NOT NULL,
|
|---|
| 828 | room_id INTEGER NOT NULL,
|
|---|
| 829 | PRIMARY KEY (room_reservation_id),
|
|---|
| 830 | CONSTRAINT uq_roomreservation_reservation
|
|---|
| 831 | UNIQUE (reservation_id),
|
|---|
| 832 | CONSTRAINT chk_roomres_dates
|
|---|
| 833 | CHECK (check_out_date > check_in_date),
|
|---|
| 834 | CONSTRAINT fk_roomres_room
|
|---|
| 835 | FOREIGN KEY (room_id) REFERENCES Room(room_id)
|
|---|
| 836 | ON DELETE RESTRICT ON UPDATE CASCADE,
|
|---|
| 837 | CONSTRAINT fk_roomres_reservation
|
|---|
| 838 | FOREIGN KEY (reservation_id) REFERENCES Reservation(reservation_id)
|
|---|
| 839 | ON DELETE CASCADE ON UPDATE CASCADE
|
|---|
| 840 | );
|
|---|
| 841 |
|
|---|
| 842 | -- Step 3: Recreate Date table
|
|---|
| 843 | CREATE TABLE Date (
|
|---|
| 844 | date DATE NOT NULL,
|
|---|
| 845 | room_id INTEGER NOT NULL,
|
|---|
| 846 | status VARCHAR(20),
|
|---|
| 847 | PRIMARY KEY (date, room_id),
|
|---|
| 848 | CONSTRAINT fk_dates_room
|
|---|
| 849 | FOREIGN KEY (room_id) REFERENCES Room(room_id)
|
|---|
| 850 | ON DELETE RESTRICT ON UPDATE CASCADE
|
|---|
| 851 | );
|
|---|
| 852 |
|
|---|
| 853 | -- Step 4: Insert RoomReservations
|
|---|
| 854 | SET work_mem = '512MB';
|
|---|
| 855 | SET synchronous_commit = OFF;
|
|---|
| 856 |
|
|---|
| 857 | DO $$
|
|---|
| 858 | BEGIN
|
|---|
| 859 | FOR iter IN 0..99 LOOP
|
|---|
| 860 | INSERT INTO RoomReservation (
|
|---|
| 861 | check_in_date,
|
|---|
| 862 | check_out_date,
|
|---|
| 863 | reservation_id,
|
|---|
| 864 | room_id
|
|---|
| 865 | )
|
|---|
| 866 | WITH rooms AS (
|
|---|
| 867 | SELECT
|
|---|
| 868 | room_id,
|
|---|
| 869 | (row_number() OVER (ORDER BY room_id) - 1)::int AS room_index,
|
|---|
| 870 | count(*) OVER ()::int AS total_rooms
|
|---|
| 871 | FROM Room
|
|---|
| 872 | ),
|
|---|
| 873 | reservations AS (
|
|---|
| 874 | SELECT
|
|---|
| 875 | reservation_id,
|
|---|
| 876 | reservation_date,
|
|---|
| 877 | (row_number() OVER (ORDER BY reservation_id) - 1)::int AS res_index
|
|---|
| 878 | FROM (
|
|---|
| 879 | SELECT reservation_id, reservation_date
|
|---|
| 880 | FROM Reservation
|
|---|
| 881 | ORDER BY reservation_id
|
|---|
| 882 | LIMIT 100000
|
|---|
| 883 | OFFSET (iter * 100000)
|
|---|
| 884 | ) x
|
|---|
| 885 | ),
|
|---|
| 886 | assigned AS (
|
|---|
| 887 | SELECT
|
|---|
| 888 | r.reservation_id,
|
|---|
| 889 | r.reservation_date,
|
|---|
| 890 | rm.room_id,
|
|---|
| 891 | floor(random() * 6 + 1)::int AS stay_length
|
|---|
| 892 | FROM reservations r
|
|---|
| 893 | JOIN rooms rm
|
|---|
| 894 | ON rm.room_index = r.res_index % rm.total_rooms
|
|---|
| 895 | ),
|
|---|
| 896 | scheduled AS (
|
|---|
| 897 | SELECT
|
|---|
| 898 | reservation_id,
|
|---|
| 899 | room_id,
|
|---|
| 900 | reservation_date AS check_in_date,
|
|---|
| 901 | reservation_date + stay_length AS check_out_date
|
|---|
| 902 | FROM assigned
|
|---|
| 903 | )
|
|---|
| 904 | SELECT
|
|---|
| 905 | check_in_date,
|
|---|
| 906 | check_out_date,
|
|---|
| 907 | reservation_id,
|
|---|
| 908 | room_id
|
|---|
| 909 | FROM scheduled
|
|---|
| 910 | ON CONFLICT (reservation_id) DO NOTHING;
|
|---|
| 911 |
|
|---|
| 912 | RAISE NOTICE 'Completed iteration % of 99 (offset %)', iter, iter * 100000;
|
|---|
| 913 | END LOOP;
|
|---|
| 914 | END;
|
|---|
| 915 | $$;
|
|---|
| 916 |
|
|---|
| 917 | -- Step 5: Verify RoomReservation
|
|---|
| 918 | SELECT COUNT(*) FROM RoomReservation; -- should be ~10,000,000
|
|---|
| 919 | SELECT MIN(check_in_date), MAX(check_out_date) FROM RoomReservation; -- should be within 2015-2027
|
|---|
| 920 |
|
|---|
| 921 | -- Step 6: Insert Date table
|
|---|
| 922 | DO $$
|
|---|
| 923 | DECLARE
|
|---|
| 924 | r_min INTEGER;
|
|---|
| 925 | r_max INTEGER;
|
|---|
| 926 | batch_size INTEGER := 100;
|
|---|
| 927 | cur INTEGER;
|
|---|
| 928 | BEGIN
|
|---|
| 929 | SELECT MIN(room_id), MAX(room_id) INTO r_min, r_max FROM Room;
|
|---|
| 930 | cur := r_min;
|
|---|
| 931 |
|
|---|
| 932 | WHILE cur <= r_max LOOP
|
|---|
| 933 |
|
|---|
| 934 | -- Part A: occupied nights from RoomReservation
|
|---|
| 935 | INSERT INTO Date (date, room_id, status)
|
|---|
| 936 | SELECT DISTINCT ON (gs::date, rr.room_id)
|
|---|
| 937 | gs::date,
|
|---|
| 938 | rr.room_id,
|
|---|
| 939 | 'occupied'
|
|---|
| 940 | FROM RoomReservation rr
|
|---|
| 941 | CROSS JOIN LATERAL generate_series(
|
|---|
| 942 | rr.check_in_date,
|
|---|
| 943 | rr.check_out_date - 1,
|
|---|
| 944 | interval '1 day'
|
|---|
| 945 | ) gs
|
|---|
| 946 | WHERE rr.room_id BETWEEN cur AND cur + batch_size - 1
|
|---|
| 947 | ORDER BY gs::date, rr.room_id
|
|---|
| 948 | ON CONFLICT (date, room_id) DO UPDATE SET status = 'occupied';
|
|---|
| 949 |
|
|---|
| 950 | -- Part B: fill remaining dates as available/maintenance
|
|---|
| 951 | INSERT INTO Date (date, room_id, status)
|
|---|
| 952 | SELECT
|
|---|
| 953 | d::date,
|
|---|
| 954 | r.room_id,
|
|---|
| 955 | (ARRAY['available','available','available','maintenance'])[floor(random()*4+1)::int]
|
|---|
| 956 | FROM Room r
|
|---|
| 957 | CROSS JOIN generate_series(
|
|---|
| 958 | DATE '2015-01-01',
|
|---|
| 959 | DATE '2027-12-31',
|
|---|
| 960 | interval '1 day'
|
|---|
| 961 | ) AS d
|
|---|
| 962 | WHERE r.room_id BETWEEN cur AND cur + batch_size - 1
|
|---|
| 963 | ON CONFLICT (date, room_id) DO NOTHING;
|
|---|
| 964 |
|
|---|
| 965 | RAISE NOTICE 'Processed rooms % to %', cur, cur + batch_size - 1;
|
|---|
| 966 | cur := cur + batch_size;
|
|---|
| 967 |
|
|---|
| 968 | END LOOP;
|
|---|
| 969 | END;
|
|---|
| 970 | $$;
|
|---|
| 971 |
|
|---|
| 972 | -- Step 7: Reset settings
|
|---|
| 973 | SET synchronous_commit = ON;
|
|---|
| 974 | SET work_mem = '4MB';
|
|---|
| 975 |
|
|---|
| 976 | -- Step 8: Verify Date table
|
|---|
| 977 | SELECT COUNT(*) FROM Date; -- should be ~11,870,000
|
|---|
| 978 | SELECT MIN(date), MAX(date) FROM Date; -- should be 2015-01-01 to 2027-12-31
|
|---|
| 979 |
|
|---|
| 980 |
|
|---|
| 981 |
|
|---|
| 982 |
|
|---|
| 983 |
|
|---|
| 984 | SELECT 'Species' AS table_name, COUNT(*) FROM Species UNION ALL
|
|---|
| 985 | SELECT 'Breed', COUNT(*) FROM Breed UNION ALL
|
|---|
| 986 | SELECT 'Category', COUNT(*) FROM Category UNION ALL
|
|---|
| 987 | SELECT 'Room_Type', COUNT(*) FROM Room_Type UNION ALL
|
|---|
| 988 | SELECT 'Service', COUNT(*) FROM Service UNION ALL
|
|---|
| 989 | SELECT 'Hotel', COUNT(*) FROM Hotel UNION ALL
|
|---|
| 990 | SELECT 'Employee', COUNT(*) FROM Employee UNION ALL
|
|---|
| 991 | SELECT 'Room', COUNT(*) FROM Room UNION ALL
|
|---|
| 992 | SELECT 'Customer', COUNT(*) FROM Customer UNION ALL
|
|---|
| 993 | SELECT 'Pet', COUNT(*) FROM Pet UNION ALL
|
|---|
| 994 | SELECT 'Product', COUNT(*) FROM Product UNION ALL
|
|---|
| 995 | SELECT 'Supplier', COUNT(*) FROM Supplier UNION ALL
|
|---|
| 996 | SELECT 'Order', COUNT(*) FROM "Order" UNION ALL
|
|---|
| 997 | SELECT 'OrderProduct', COUNT(*) FROM OrderProduct UNION ALL
|
|---|
| 998 | SELECT 'Delivery', COUNT(*) FROM Delivery UNION ALL
|
|---|
| 999 | SELECT 'Reservation', COUNT(*) FROM Reservation UNION ALL
|
|---|
| 1000 | SELECT 'RoomReservation', COUNT(*) FROM RoomReservation UNION ALL
|
|---|
| 1001 | SELECT 'ServiceReservation', COUNT(*) FROM ServiceReservation UNION ALL
|
|---|
| 1002 | SELECT 'Payment', COUNT(*) FROM Payment UNION ALL
|
|---|
| 1003 | SELECT 'Review', COUNT(*) FROM Review UNION ALL
|
|---|
| 1004 | SELECT 'MedicalRecord', COUNT(*) FROM MedicalRecord UNION ALL
|
|---|
| 1005 | SELECT 'PetDelivery', COUNT(*) FROM PetDelivery UNION ALL
|
|---|
| 1006 | SELECT 'Date', COUNT(*) FROM Date
|
|---|
| 1007 | ORDER BY table_name; |
|---|