DatabaseCreation: data_insertion.sql

File data_insertion.sql, 28.3 KB (added by 231056, 7 days ago)
Line 
1CREATE TABLE temp_city_import (
2 city TEXT,
3 country TEXT
4);
5
6--country 242
7INSERT INTO country (country_name)
8SELECT DISTINCT TRIM(country)
9FROM temp_city_import
10WHERE country IS NOT NULL
11ON CONFLICT (country_name) DO NOTHING;
12
13--city 45 000
14INSERT INTO city (city_name, postal_code, country_id)
15SELECT
16 city_name,
17 LPAD((FLOOR(RANDOM() * 10000))::TEXT, 4, '0'),
18 country_id
19FROM (
20 SELECT DISTINCT
21 TRIM(tci.city) AS city_name,
22 c.country_id
23 FROM temp_city_import tci
24 JOIN country c
25 ON TRIM(tci.country) = TRIM(c.country_name)
26 WHERE tci.city IS NOT NULL
27 AND tci.country IS NOT NULL
28) unique_cities
29ON CONFLICT (city_name, country_id) DO NOTHING;
30
31
32-- venues 200
33create table temp_venue_import (title text, address text);
34
35INSERT INTO venue (venue_title, street_address, capacity, city_id)
36SELECT
37 tvi.title,
38 tvi.address,
39 (FLOOR(RANDOM() * 19) * 1000 + 2000)::INT,
40 (
41 SELECT city_id
42 FROM city
43 WHERE tvi.title IS NOT NULL
44 ORDER BY RANDOM()
45 LIMIT 1
46 )
47FROM temp_venue_import tvi
48WHERE tvi.title IS NOT NULL
49 AND tvi.address IS NOT NULL
50LIMIT 200;
51
52
53-- seat 2 281 000 (sum of capacities of venues)
54INSERT INTO seat (seat_number, row_number, section, section_type, venue_id)
55SELECT
56 s.seat_num,
57 r.row_num,
58 st.sec_id,
59 st.type_name,
60 v.venue_id
61FROM venue v
62CROSS JOIN LATERAL (
63 VALUES
64 (1, 'VIP', 0.10, 10), -- 10% капацитет, 10 во ред
65 (2, 'REGULAR', 0.70, 20), -- 70% капацитет, 20 во ред
66 (3, 'BALCONY', 0.20, 20) -- 20% капацитет, 20 во ред
67) AS st(sec_id, type_name, percent, seats_per_row)
68CROSS JOIN LATERAL (
69 -- Бидејќи (capacity * percent) е секогаш делливо со seats_per_row, нема да имаме децимали
70 SELECT generate_series(1, ((v.capacity * st.percent) / st.seats_per_row)::INT) AS row_num
71) AS r
72CROSS JOIN LATERAL (
73 SELECT generate_series(1, st.seats_per_row) AS seat_num
74) AS s
75WHERE v.capacity > 0;
76
77
78-- sponsor type 7
79INSERT INTO sponsor_type (sponsor_type_name, description)
80VALUES
81('Gold', 'High-level sponsor with major visibility'),
82('Silver', 'Mid-level sponsor with moderate visibility'),
83('Bronze', 'Basic sponsorship level with limited visibility'),
84('Platinum', 'Top-tier exclusive sponsor'),
85('Corporate', 'Large company supporting the event'),
86('Media', 'Provides media coverage and promotion'),
87('Event', 'Sponsors a specific event');
88
89
90
91-- sponsor 2000
92CREATE TABLE temp_company_names (
93 company_name TEXT
94);
95
96INSERT INTO sponsor (sponsor_name, contact_email, website, sponsor_type_id)
97SELECT
98 tcn.company_name,
99 lower(replace(tcn.company_name, ' ', '.')) || '@businessmail.com' AS contact_email,
100 'https://www.' || lower(replace(tcn.company_name, ' ', '')) || '.com' AS website,
101 (
102 SELECT sponsor_type_id
103 FROM sponsor_type
104 WHERE tcn.company_name IS NOT NULL
105 ORDER BY random()
106 LIMIT 1
107 ) AS sponsor_type_id
108FROM temp_company_names tcn
109WHERE tcn.company_name IS NOT NULL;
110
111SELECT * FROM sponsor;
112
113
114-- ticket type 5
115INSERT INTO ticket_type (type_name) VALUES
116('Standard'),
117('VIP'),
118('Student'),
119('Child'),
120('Group');
121
122
123
124
125-- category
126
127-- 1. PARENT CATEGORIES
128INSERT INTO category (category_name, category_description, parent_category_id) VALUES
129('Events', 'All types of public and private events', NULL),
130('Entertainment', 'Shows, concerts, movies and performances', NULL),
131('Sports', 'Sport competitions and tournaments', NULL),
132('Education', 'Learning and training activities', NULL),
133('Business', 'Corporate and professional events', NULL),
134('Technology', 'Tech-related events and expos', NULL),
135('Lifestyle', 'Social and lifestyle events', NULL);
136
137-- 2. EVENTS SUBCATEGORIES
138INSERT INTO category (category_name, category_description, parent_category_id) VALUES
139('Concerts', 'Live music performances', 1),
140('Festivals', 'Seasonal and cultural festivals', 1),
141('Exhibitions', 'Art and museum exhibitions', 1),
142('Fairs', 'Public fairs and trade fairs', 1),
143('Ceremonies', 'Official and private ceremonies', 1);
144
145-- 3. ENTERTAINMENT
146INSERT INTO category (category_name, category_description, parent_category_id) VALUES
147('Theater', 'Stage plays and performances', 2),
148('Cinema', 'Movie screenings and premieres', 2),
149('Comedy Shows', 'Stand-up comedy events', 2),
150('Dance Shows', 'Dance and performance shows', 2);
151
152-- 4. SPORTS
153INSERT INTO category (category_name, category_description, parent_category_id) VALUES
154('Football', 'Football matches and tournaments', 3),
155('Basketball', 'Basketball leagues and games', 3),
156('Tennis', 'Tennis tournaments', 3),
157('Athletics', 'Track and field competitions', 3),
158('Martial Arts', 'Combat sports events', 3);
159
160-- 5. EDUCATION
161INSERT INTO category (category_name, category_description, parent_category_id) VALUES
162('Workshops', 'Hands-on skill workshops', 4),
163('Seminars', 'Educational seminars and talks', 4),
164('Online Courses', 'Virtual learning sessions', 4),
165('Training Sessions', 'Professional training programs', 4),
166('Lectures', 'Academic lectures and presentations', 4);
167
168-- 6. BUSINESS
169INSERT INTO category (category_name, category_description, parent_category_id) VALUES
170('Conferences', 'Large professional conferences', 5),
171('Networking Events', 'Business networking meetups', 5),
172('Product Launches', 'New product presentations', 5),
173('Work Meetings', 'Corporate meetings and events', 5),
174('Trade Shows', 'Industry exhibitions and fairs', 5);
175
176-- 7. TECHNOLOGY
177INSERT INTO category (category_name, category_description, parent_category_id) VALUES
178('Tech Conferences', 'Technology industry conferences', 6),
179('Hackathons', 'Programming competitions', 6),
180('Startup Events', 'Startup pitching and networking', 6),
181('AI Workshops', 'Artificial intelligence learning events', 6),
182('IT Seminars', 'Information technology seminars', 6);
183
184-- 8. LIFESTYLE
185INSERT INTO category (category_name, category_description, parent_category_id) VALUES
186('Fashion Shows', 'Clothing and fashion events', 7),
187('Food Festivals', 'Food and drink festivals', 7),
188('Wellness Events', 'Health and wellness activities', 7),
189('Charity Events', 'Fundraising and charity activities', 7),
190('Social Gatherings', 'Community and social meetups', 7);
191
192
193
194-- customers 10000
195CREATE TABLE temp_name(first_name TEXT);
196CREATE TABLE temp_surname(last_name TEXT);
197
198INSERT INTO customer (email, first_name, last_name, hash_password)
199SELECT
200 LOWER(fn.first_name || '.' || ln.last_name || '@gmail.com') AS email,
201 fn.first_name,
202 ln.last_name,
203 MD5(RANDOM()::TEXT) AS hash_password
204FROM (SELECT DISTINCT first_name FROM temp_name) fn
205CROSS JOIN (SELECT DISTINCT last_name FROM temp_surname) ln
206LIMIT 10000;
207
208
209-- admins 1000
210CREATE TABLE temp_admin_name(first_name TEXT);
211CREATE TABLE temp_admin_surname(last_name TEXT);
212
213INSERT INTO admin (email, first_name, last_name, password_hash)
214SELECT
215 LOWER(fn.first_name || '.' || ln.last_name || ROW_NUMBER() OVER() || '@event.com') AS email,
216 fn.first_name,
217 ln.last_name,
218 MD5(RANDOM()::TEXT) AS password_hash
219FROM temp_admin_name fn
220CROSS JOIN temp_admin_surname ln
221LIMIT 1000;
222
223-- Event admins ~ 600
224INSERT INTO event_admin (admin_id)
225SELECT admin_id FROM admin ORDER BY RANDOM() LIMIT 600;
226
227-- Ticket admins ~ 400
228INSERT INTO ticket_admin (admin_id)
229SELECT a.admin_id
230FROM admin a
231WHERE NOT EXISTS (SELECT 1 FROM event_admin ea WHERE ea.admin_id = a.admin_id);
232
233-- 30% overlap (event admin da e i ticket admin)
234INSERT INTO ticket_admin (admin_id)
235SELECT admin_id
236FROM event_admin
237ORDER BY RANDOM()
238LIMIT (SELECT COUNT(*) * 0.3 FROM event_admin);
239
240
241
242-- discount 1200
243INSERT INTO discount (discount_code, discount_percent, event_admin_id)
244SELECT
245 'DSC' || upper(substr(md5(random()::text), 1, 4)) || row_number() OVER() AS discount_code,
246
247 CASE
248 WHEN random() < 0.45 THEN (floor(random() * 16) + 5)
249 WHEN random() < 0.75 THEN (floor(random() * 15) + 21)
250 WHEN random() < 0.92 THEN (floor(random() * 15) + 36)
251 ELSE (floor(random() * 20) + 51)
252 END AS discount_percent,
253
254 ea.admin_id
255FROM event_admin ea
256CROSS JOIN generate_series(1, 2) AS i;
257
258
259-- payment
260INSERT INTO payment (amount, payment_method, payment_status, payment_date, customer_id, discount_id)
261SELECT
262 -- Пресметка на финалниот износ (со вклучен попуст)
263 CASE
264 WHEN d.discount_percent IS NOT NULL THEN
265 -- Пример: 5000 * (1 - 20/100) = 4000
266 ((floor(random() * 471) * 10 + 300) * (1 - d.discount_percent / 100.0))::NUMERIC(10,2)
267 ELSE
268 -- Нема попуст, плаќа полна цена
269 (floor(random() * 471) * 10 + 300)::NUMERIC(10,2)
270 END AS amount,
271
272 (ARRAY['CARD','ONLINE','CASH','TRANSFER'])[FLOOR(RANDOM() * 4 + 1)::int] AS payment_method,
273
274 CASE
275 WHEN random() < 0.80 THEN 'COMPLETED'
276 WHEN random() < 0.90 THEN 'FAILED'
277 WHEN random() < 0.96 THEN 'PENDING'
278 ELSE 'REFUNDED'
279 END AS payment_status,
280
281 NOW() - (RANDOM() * INTERVAL '730 days') AS payment_date,
282
283 (FLOOR(RANDOM() * 10000) + 1)::int AS customer_id,
284
285 d.discount_id
286FROM generate_series(1, 5000000) AS s
287-- Со LEFT JOIN ги додаваме процентите на попуст за тие 15% од редовите
288LEFT JOIN (
289 SELECT discount_id, discount_percent, row_number() OVER () as rnum
290 FROM discount
291) d ON (s % 100 < 15) AND (d.rnum = (s % (SELECT count(*) FROM discount) + 1));
292
293
294-- event 1600
295INSERT INTO event (name, description, start_datetime, end_datetime, status, venue_id, category_id)
296SELECT
297 (ARRAY['Global', 'Premium', 'International', 'Live', 'Elite', 'Historic', 'Annual', 'Virtual'])[FLOOR(RANDOM() * 8 + 1)]
298 || ' ' || cat.category_name
299 || ' ' || (ARRAY['Summit', 'Festival', 'Gala', 'Masterclass', 'Experience', 'Championship'])[FLOOR(RANDOM() * 6 + 1)] AS name,
300
301 'Exclusive ' || LOWER(cat.category_name) || ' event happening at a top venue.' AS description,
302
303 eb.gen_start_dt AS start_datetime,
304 eb.gen_start_dt + (INTERVAL '1 minute' * (FLOOR(RANDOM() * 241) + 120)) AS end_datetime,
305
306 CASE
307 WHEN eb.gen_start_dt < NOW() - INTERVAL '1 day' THEN
308 CASE WHEN RANDOM() < 0.05 THEN 'CANCELLED' ELSE 'COMPLETED' END
309 WHEN eb.gen_start_dt BETWEEN NOW() - INTERVAL '1 day' AND NOW() + INTERVAL '1 day' THEN 'ONGOING'
310 ELSE 'PUBLISHED'
311 END AS status,
312
313 -- Го користиме r_idx во OFFSET за да го присилиме PostgreSQL да пребарува различно секој пат
314 (SELECT venue_id FROM venue OFFSET (eb.r_idx % (SELECT count(*) FROM venue)) LIMIT 1) as venue_id,
315
316 cat.category_id
317FROM (
318 SELECT
319 row_number() OVER () as r_idx,
320 NOW() + (INTERVAL '1 day' * (FLOOR(RANDOM() * 600) - 400))
321 + (INTERVAL '1 minute' * FLOOR(RANDOM() * 1440)) AS gen_start_dt
322 FROM generate_series(1, 1200)
323) eb
324CROSS JOIN LATERAL (
325 SELECT category_id, category_name
326 FROM category
327 WHERE parent_category_id IS NOT NULL
328 -- Овде додаваме услов кој зависи од eb.r_idx за да спречиме кеширање
329 AND eb.r_idx IS NOT NULL
330 ORDER BY RANDOM()
331 LIMIT 1
332) cat;
333
334
335-- event_manages ~2421
336INSERT INTO event_manages (event_id, event_admin_id)
337SELECT
338 e.event_id,
339 adm.admin_id
340FROM event e
341CROSS JOIN LATERAL (
342 -- Ова подпрашање генерира случаен број на админи (1-3) за секој настан
343 SELECT ea.admin_id
344 FROM event_admin ea
345 WHERE e.event_id IS NOT NULL -- Го присилуваме ре-евалуирањето за секој настан
346 ORDER BY RANDOM()
347 LIMIT (FLOOR(RANDOM() * 3) + 1) -- Секој настан ќе има 1, 2 или 3 админи
348) adm;
349
350
351-- event sponsorship ~ 120 000
352INSERT INTO event_sponsorship (sponsor_id, event_id, sponsorship_amount, contract_date)
353SELECT DISTINCT ON (e.event_id, rand_s.sponsor_id)
354 rand_s.sponsor_id,
355 e.event_id,
356 (FLOOR(RANDOM() * 14501) * 10 + 5000)::NUMERIC(12,2) AS sponsorship_amount,
357 LEAST(
358 NOW(),
359 e.start_datetime - (INTERVAL '1 day' * (FLOOR(RANDOM() * 30) + 5))
360 ) - (INTERVAL '1 day' * FLOOR(RANDOM() * 60)) AS contract_date
361
362FROM event e
363CROSS JOIN LATERAL generate_series(1, 100) AS s_count
364CROSS JOIN LATERAL (
365 SELECT s.sponsor_id
366 FROM sponsor s
367 WHERE e.event_id IS NOT NULL
368 ORDER BY RANDOM()
369 LIMIT (FLOOR(RANDOM() * 51) + 50)
370) rand_s;
371
372
373-- event media
374INSERT INTO event_media (url, event_id)
375SELECT
376 'https://picsum.photos/seed/' || e.event_id || '-' || s.idx || '/1200/800' AS url,
377 e.event_id
378FROM event e
379CROSS JOIN LATERAL (
380 -- Генерираме случаен број на слики (помеѓу 20 и 50) за секој настан
381 SELECT generate_series(1, (FLOOR(RANDOM() * 31) + 20)::INT) AS idx
382) s;
383
384
385-- Поправка на payment бидејќи сите редици имаат discount id и се користат само првите 15 discount кодови
386
387DO $$
388DECLARE
389 total_discounts INT;
390BEGIN
391 SELECT count(*) INTO total_discounts FROM discount;
392
393 -- 1. Прво ги ресетираме сите на NULL за да нема грешки од претходно
394 UPDATE payment SET discount_id = NULL;
395
396 -- 2. Ажурираме 15% од редовите со вистински попусти (користиме batches за брзина)
397 -- Ова ќе ги искористи сите 1200 кодови (payment_id % total_discounts)
398 UPDATE payment
399 SET discount_id = (payment_id % total_discounts) + 1
400 WHERE payment_id % 100 < 15;
401
402 -- 3. Го средуваме amount во payment:
403 -- Ако е NULL, ставаме полна цена. Ако има попуст, amount веќе се смета за платена сума
404 UPDATE payment p
405 SET amount = (floor(random() * 471) * 10 + 300)::NUMERIC(10,2)
406 WHERE p.discount_id IS NULL;
407
408 COMMIT;
409END $$;
410
411
412-- tickets
413
414--Проверка само за еден настан
415
416DO $$
417DECLARE
418 r_event RECORD;
419 v_total_seats INT;
420 v_to_fill INT;
421 v_offset_completed INT := 0;
422 v_offset_refunded INT := 0;
423 v_total_refunded INT := 3926;
424BEGIN
425 FOR r_event IN (SELECT event_id, venue_id, start_datetime, end_datetime, status as event_status FROM event ORDER BY start_datetime ASC LIMIT 1) LOOP
426
427 SELECT count(*) INTO v_total_seats FROM seat WHERE venue_id = r_event.venue_id;
428
429 IF r_event.start_datetime > '2026-05-01' THEN
430 v_to_fill := floor(v_total_seats * (random() * 0.15 + 0.05));
431 ELSE
432 v_to_fill := floor(v_total_seats * (random() * 0.55 + 0.30));
433 END IF;
434
435 INSERT INTO ticket (
436 status, reserved_at, expires_at, purchased_at,
437 ticket_price, qr_code, customer_id, seat_id,
438 event_id, ticket_type_id, payment_id
439 )
440 SELECT
441 CASE
442 WHEN r_event.event_status = 'CANCELLED' THEN 'CANCELLED'
443 WHEN p.payment_id IS NOT NULL THEN
444 (CASE WHEN r_event.end_datetime < NOW() THEN 'SCANNED' ELSE 'PURCHASED' END)
445 WHEN r_event.end_datetime < NOW() THEN 'CANCELLED'
446 WHEN s.rn <= v_to_fill THEN 'RESERVED'
447 ELSE 'AVAILABLE'
448 END,
449
450 CASE
451 WHEN p.payment_id IS NOT NULL THEN LEAST(p.payment_date, r_event.start_datetime) - INTERVAL '25 minutes'
452 WHEN s.rn <= v_to_fill AND r_event.end_datetime > NOW() AND r_event.event_status != 'CANCELLED' THEN NOW() - INTERVAL '10 minutes'
453 ELSE NULL
454 END,
455 r_event.end_datetime,
456
457 CASE
458 WHEN p.payment_id IS NOT NULL THEN LEAST(p.payment_date, r_event.end_datetime - INTERVAL '1 minute')
459 ELSE NULL
460 END,
461 CASE
462 WHEN d.discount_percent IS NOT NULL THEN (p.amount / (1.0 - (d.discount_percent / 100.0)))::NUMERIC(10,2)
463 WHEN p.payment_id IS NOT NULL THEN p.amount
464 ELSE (FLOOR(RANDOM() * 400) + 250)::NUMERIC(10,2)
465 END,
466 md5(r_event.event_id::text || s.seat_id::text || random()::text),
467 p.customer_id, s.seat_id, r_event.event_id, 1, p.payment_id
468 FROM (
469 SELECT seat_id, ROW_NUMBER() OVER (ORDER BY seat_id) as rn
470 FROM seat WHERE venue_id = r_event.venue_id
471 ) s
472 LEFT JOIN LATERAL (
473 SELECT payment_id, amount, customer_id, payment_date, discount_id, payment_status
474 FROM payment
475 WHERE
476 (r_event.event_status = 'CANCELLED' AND payment_status = 'REFUNDED' AND payment_id > v_offset_refunded)
477 OR
478 (r_event.event_status != 'CANCELLED' AND payment_status = 'COMPLETED' AND payment_id > v_offset_completed)
479 ORDER BY payment_id
480 LIMIT 1 OFFSET (s.rn - 1)
481 ) p ON s.rn <= CASE WHEN r_event.event_status = 'CANCELLED' THEN 85 ELSE floor(v_to_fill * 0.8) END
482 LEFT JOIN discount d ON p.discount_id = d.discount_id;
483
484 RAISE NOTICE 'Тестот е готов за настанот: %', r_event.event_id;
485 END LOOP;
486END $$;
487
488
489-- Сите настани по batches
490
491-- 1. Креираме привремена копија на плаќањата подредени по редослед
492DROP TABLE IF EXISTS temp_pay_queue;
493CREATE TEMP TABLE temp_pay_queue AS
494SELECT payment_id, amount, customer_id, payment_date, payment_status,
495 ROW_NUMBER() OVER (PARTITION BY payment_status ORDER BY payment_id) as rn
496FROM payment;
497
498-- 2. Овој индекс е САМО за оваа привремена табела
499CREATE INDEX idx_temp_pay_rn ON temp_pay_queue(payment_status, rn);
500
501
502DO $$
503DECLARE
504 r_event RECORD;
505 v_total_seats INT;
506 v_to_fill INT;
507 v_event_counter INT := 0;
508 v_pay_ptr INT := 1; -- Почнуваме од првото COMPLETED плаќање во temp табелата
509 v_ref_ptr INT := 1; -- Почнуваме од првото REFUNDED плаќање во temp табелата
510BEGIN
511
512 TRUNCATE TABLE ticket RESTART IDENTITY CASCADE;
513
514 FOR r_event IN (
515 SELECT event_id, venue_id, start_datetime, end_datetime, status as event_status
516 FROM event
517 ORDER BY start_datetime ASC
518 ) LOOP
519
520 -- 1. Земи капацитет за венеуто на настанот
521 SELECT count(*) INTO v_total_seats FROM seat WHERE venue_id = r_event.venue_id;
522
523 -- 2. Одреди колку вкупно седишта ќе бидат „зафатени“ (продадени/резервирани)
524 IF r_event.start_datetime > '2026-05-01' THEN
525 v_to_fill := floor(v_total_seats * (random() * 0.15 + 0.05));
526 ELSE
527 v_to_fill := floor(v_total_seats * (random() * 0.55 + 0.30));
528 END IF;
529
530 -- 3. Полнење на TICKET
531 INSERT INTO ticket (
532 status, reserved_at, expires_at, purchased_at,
533 ticket_price, qr_code, customer_id, seat_id,
534 event_id, ticket_type_id, payment_id
535 )
536 SELECT
537 CASE
538 WHEN r_event.event_status = 'CANCELLED' THEN 'CANCELLED'
539 WHEN tp.payment_id IS NOT NULL THEN
540 (CASE WHEN r_event.end_datetime < NOW() THEN 'SCANNED' ELSE 'PURCHASED' END)
541 WHEN s.rn <= v_to_fill AND r_event.end_datetime > NOW() THEN 'RESERVED'
542 ELSE 'AVAILABLE'
543 END,
544 -- Reserved_at
545 CASE
546 WHEN tp.payment_id IS NOT NULL THEN LEAST(tp.payment_date, r_event.start_datetime) - INTERVAL '25 minutes'
547 WHEN s.rn <= v_to_fill AND r_event.end_datetime > NOW() THEN NOW() - INTERVAL '10 minutes'
548 ELSE NULL
549 END,
550 r_event.end_datetime, -- Expires_at
551 -- Purchased_at
552 CASE
553 WHEN tp.payment_id IS NOT NULL THEN LEAST(tp.payment_date, r_event.end_datetime - INTERVAL '1 minute')
554 ELSE NULL
555 END,
556 -- Цена (од плаќање или рандом)
557 COALESCE(tp.amount, (FLOOR(RANDOM() * 400) + 250)::NUMERIC(10,2)),
558 md5(r_event.event_id::text || s.seat_id::text || random()::text),
559 tp.customer_id, s.seat_id, r_event.event_id, 1, tp.payment_id
560 FROM (
561 SELECT seat_id, ROW_NUMBER() OVER (ORDER BY seat_id) as rn
562 FROM seat WHERE venue_id = r_event.venue_id
563 ) s
564 LEFT JOIN temp_pay_queue tp ON
565 (
566 r_event.event_status = 'CANCELLED'
567 AND tp.payment_status = 'REFUNDED'
568 AND tp.rn = (v_ref_ptr + s.rn - 1)
569 AND s.rn <= 85 -- Земи точно 85 рефундирани за откажан настан
570 )
571 OR
572 (
573 r_event.event_status != 'CANCELLED'
574 AND tp.payment_status = 'COMPLETED'
575 AND tp.rn = (v_pay_ptr + s.rn - 1)
576 AND s.rn <= floor(v_to_fill * 0.8) -- 80% од пополнетоста се продадени
577 )
578 WHERE s.rn <= v_total_seats;
579
580 -- 4. Помести ги покажувачите за следниот настан
581 IF r_event.event_status = 'CANCELLED' THEN
582 v_ref_ptr := v_ref_ptr + 85;
583 ELSE
584 v_pay_ptr := v_pay_ptr + floor(v_to_fill * 0.8);
585 END IF;
586
587 v_event_counter := v_event_counter + 1;
588
589 -- Известување за прогрес
590 IF v_event_counter % 1 = 0 THEN
591 RAISE NOTICE 'Настан % завршен (ID: %). Вкупно тикети: %',
592 v_event_counter, r_event.event_id, (SELECT count(*) FROM ticket);
593 COMMIT;
594 END IF;
595 END LOOP;
596
597 RAISE NOTICE 'Процесот е комплетиран успешно!';
598END $$;
599
600
601-- review
602TRUNCATE TABLE review RESTART IDENTITY CASCADE;
603
604INSERT INTO review (rating, comment, customer_id, event_id)
605SELECT
606 v.rating,
607 CASE
608 -- 35% од луѓето не оставаат коментар (NULL)
609 WHEN (random() * 100)::int % 3 = 0 THEN NULL
610
611 -- Позитивни (4 и 5)
612 WHEN v.rating >= 4 THEN
613 (ARRAY['Amazing experience!', 'Great organization.', 'The sound was perfect.', 'Loved every second!', 'Unforgettable night.', 'Everything was spot on!', 'Fantastic atmosphere.', 'Would come again!'])[floor(random() * 8 + 1)]
614
615 -- Неутрални (3)
616 WHEN v.rating = 3 THEN
617 (ARRAY['Good but crowded.', 'Average experience.', 'Solid performance.', 'It was okay.'])[floor(random() * 4 + 1)]
618
619 -- Негативни (1 и 2)
620 ELSE
621 (ARRAY['Disappointing.', 'Could be much better.', 'Not worth the money.', 'Bad organization.', 'Sound was terrible.'])[floor(random() * 5 + 1)]
622 END AS comment,
623 v.customer_id,
624 v.event_id
625FROM (
626 -- Ова под-барање гарантира дека RANDOM() се повикува за СЕКОЈ ред посебно
627 SELECT
628 customer_id,
629 event_id,
630 (CASE
631 WHEN random() < 0.5 THEN (floor(random() * 2) + 4)::SMALLINT -- 50% шанса за 4 или 5
632 WHEN random() < 0.8 THEN 3::SMALLINT -- 30% шанса за 3
633 ELSE (floor(random() * 2) + 1)::SMALLINT -- 20% шанса за 1 или 2
634 END) AS rating
635 FROM ticket
636 WHERE status = 'SCANNED'
637) v
638ON CONFLICT (customer_id, event_id) DO NOTHING;
639
640
641-- notification
642INSERT INTO notification (title, message, created_at, is_read, customer_id, event_id)
643SELECT
644 'New Event Alert: ' || e.name,
645 'Hey ' || c.first_name || ', a new event "' || e.name || '" has been published! Book your tickets now.',
646 -- Ова гарантира дека created_at никогаш нема да го помине денешниот датум
647 LEAST(e.start_datetime - INTERVAL '30 days', CURRENT_TIMESTAMP),
648 -- Прочитано само ако е навистина старо
649 (LEAST(e.start_datetime - INTERVAL '30 days', CURRENT_TIMESTAMP) < NOW() - INTERVAL '1 month'),
650 c.customer_id,
651 e.event_id
652FROM event e
653CROSS JOIN customer c
654WHERE e.status = 'PUBLISHED';
655
656INSERT INTO notification (title, message, created_at, is_read, customer_id, event_id)
657SELECT
658 'Event Cancelled: ' || e.name,
659 'Dear ' || c.first_name || ', we regret to inform you that "' || e.name || '" has been cancelled. Your refund is processed.',
660 -- Известувањето се пратило 2 дена пред планираниот почеток, но не подоцна од СЕГА
661 LEAST(e.start_datetime - INTERVAL '2 days', CURRENT_TIMESTAMP),
662 -- Бидејќи е итна вест, претпоставуваме дека 95% ја прочитале ако поминал 1 ден
663 (LEAST(e.start_datetime - INTERVAL '2 days', CURRENT_TIMESTAMP) < NOW() - INTERVAL '1 day'),
664 t.customer_id,
665 e.event_id
666FROM ticket t
667JOIN event e ON t.event_id = e.event_id
668JOIN customer c ON t.customer_id = c.customer_id
669WHERE t.status = 'CANCELLED';
670
671INSERT INTO notification (title, message, created_at, is_read, customer_id, event_id)
672SELECT
673 'How was ' || e.name || '?',
674 'Hi ' || c.first_name || ', share your experience! Leave a review for "' || e.name || '" and help others.',
675 -- Нотификацијата се праќа 2 часа по завршувањето на настанот
676 LEAST(e.end_datetime + INTERVAL '2 hours', CURRENT_TIMESTAMP),
677 -- Прочитани се ако поминале повеќе од 2 недели од праќањето
678 (LEAST(e.end_datetime + INTERVAL '2 hours', CURRENT_TIMESTAMP) < NOW() - INTERVAL '14 days'),
679 t.customer_id,
680 e.event_id
681FROM ticket t
682JOIN event e ON t.event_id = e.event_id
683JOIN customer c ON t.customer_id = c.customer_id
684WHERE t.status = 'SCANNED';
685
686
687INSERT INTO notification (title, message, created_at, is_read, customer_id, event_id)
688SELECT
689 'Starting Soon: ' || e.name,
690 'Hey ' || c.first_name || ', get ready! "' || e.name || '" starts in 1 hour. Have your QR code ready!',
691 -- Се праќа точно 1 час пред почетокот
692 LEAST(e.start_datetime - INTERVAL '1 hour', CURRENT_TIMESTAMP),
693 -- Скоро секогаш е FALSE (непрочитано), освен ако настанот веќе почнал одамна
694 (LEAST(e.start_datetime - INTERVAL '1 hour', CURRENT_TIMESTAMP) < NOW() - INTERVAL '1 day'),
695 t.customer_id,
696 e.event_id
697FROM ticket t
698JOIN event e ON t.event_id = e.event_id
699JOIN customer c ON t.customer_id = c.customer_id
700WHERE t.status = 'PURCHASED';
701
702-- seat reservation
703INSERT INTO seat_reservation (reserved_at, status, seat_id, ticket_id)
704SELECT
705 -- Ако нема reserved_at, земи purchased_at, ако нема и тоа, стави 2 часа пред почеток на настанот
706 COALESCE(t.reserved_at, t.purchased_at, e.start_datetime - INTERVAL '2 hours'),
707 CASE
708 WHEN t.status = 'RESERVED' THEN 'ACTIVE'
709 WHEN t.status = 'CANCELLED' THEN 'CANCELLED'
710 ELSE 'EXPIRED'
711 END,
712 t.seat_id,
713 t.ticket_id
714FROM ticket t
715JOIN event e ON t.event_id = e.event_id
716WHERE t.status != 'AVAILABLE';
717
718INSERT INTO seat_reservation (reserved_at, status, seat_id, ticket_id)
719SELECT
720 COALESCE(t.reserved_at, t.purchased_at, e.start_datetime - INTERVAL '2 hours') - INTERVAL '45 minutes',
721 'EXPIRED',
722 t.seat_id,
723 t.ticket_id
724FROM ticket t
725JOIN event e ON t.event_id = e.event_id
726WHERE t.status != 'AVAILABLE'
727ORDER BY random()
728LIMIT 1000000;
729
730
731
732-- Бришење на temp табелите
733DROP TABLE IF EXISTS temp_city_import, temp_venue_import, temp_name, temp_surname, temp_company_names, temp_admin_name, temp_admin_surname;