| 1 | CREATE INDEX IF NOT EXISTS idx_ticket_screening ON TICKET(screening_id);
|
|---|
| 2 | CREATE INDEX IF NOT EXISTS idx_ticket_user ON TICKET(user_id);
|
|---|
| 3 | CREATE INDEX IF NOT EXISTS idx_ticket_seat ON TICKET(seat_id);
|
|---|
| 4 | CREATE INDEX IF NOT EXISTS idx_screening_movie ON SCREENING(movie_id);
|
|---|
| 5 | CREATE INDEX IF NOT EXISTS idx_screening_hall ON SCREENING(cinemahall_id);
|
|---|
| 6 | CREATE INDEX IF NOT EXISTS idx_screening_date ON SCREENING("date");
|
|---|
| 7 | CREATE INDEX IF NOT EXISTS idx_screening_time ON SCREENING("time");
|
|---|
| 8 | CREATE INDEX IF NOT EXISTS idx_review_movie ON REVIEW(movie_id);
|
|---|
| 9 | CREATE INDEX IF NOT EXISTS idx_reservation_status ON RESERVATION(status);
|
|---|
| 10 | CREATE INDEX IF NOT EXISTS idx_purchased_product_ticket ON PURCHASED_PRODUCT(ticket_id);
|
|---|
| 11 | CREATE INDEX IF NOT EXISTS idx_purchased_product_product ON PURCHASED_PRODUCT(product_id);
|
|---|
| 12 | CREATE INDEX IF NOT EXISTS idx_movie_genre_movie ON MOVIE_GENRE(movie_id);
|
|---|
| 13 | CREATE INDEX IF NOT EXISTS idx_movie_genre_genre ON MOVIE_GENRE(genre_id);
|
|---|
| 14 |
|
|---|
| 15 | DROP MATERIALIZED VIEW IF EXISTS mat_movie_revenue CASCADE;
|
|---|
| 16 | DROP MATERIALIZED VIEW IF EXISTS mat_most_watched_genre CASCADE;
|
|---|
| 17 | DROP MATERIALIZED VIEW IF EXISTS mat_busiest_months CASCADE;
|
|---|
| 18 | DROP MATERIALIZED VIEW IF EXISTS mat_cinema_revenue CASCADE;
|
|---|
| 19 | DROP MATERIALIZED VIEW IF EXISTS mat_hall_occupancy CASCADE;
|
|---|
| 20 | DROP MATERIALIZED VIEW IF EXISTS mat_top_products CASCADE;
|
|---|
| 21 | DROP MATERIALIZED VIEW IF EXISTS mat_promotion_impact CASCADE;
|
|---|
| 22 | DROP MATERIALIZED VIEW IF EXISTS mat_reservation_status CASCADE;
|
|---|
| 23 | DROP MATERIALIZED VIEW IF EXISTS mat_popular_time_slots CASCADE;
|
|---|
| 24 | DROP MATERIALIZED VIEW IF EXISTS mat_product_vs_ticket_revenue CASCADE;
|
|---|
| 25 | DROP MATERIALIZED VIEW IF EXISTS mat_morning_vs_evening CASCADE;
|
|---|
| 26 | DROP MATERIALIZED VIEW IF EXISTS mat_movie_review_stats CASCADE;
|
|---|
| 27 | DROP MATERIALIZED VIEW IF EXISTS mat_genre_review_stats CASCADE;
|
|---|
| 28 |
|
|---|
| 29 | -- 1. Priod po film
|
|---|
| 30 | CREATE MATERIALIZED VIEW mat_movie_revenue AS
|
|---|
| 31 | SELECT m.title,
|
|---|
| 32 | COUNT(t.ticket_id) AS total_tickets,
|
|---|
| 33 | SUM(t.price) AS total_revenue,
|
|---|
| 34 | ROUND(AVG(t.price)::numeric, 2) AS avg_ticket_price
|
|---|
| 35 | FROM MOVIE m
|
|---|
| 36 | JOIN SCREENING s ON s.movie_id = m.movie_id
|
|---|
| 37 | JOIN TICKET t ON t.screening_id = s.screening_id
|
|---|
| 38 | GROUP BY m.title
|
|---|
| 39 | ORDER BY total_revenue DESC;
|
|---|
| 40 |
|
|---|
| 41 | -- 2. Najgledan zanr (bez DISTINCT i bez LEFT JOIN)
|
|---|
| 42 | CREATE MATERIALIZED VIEW mat_most_watched_genre AS
|
|---|
| 43 | SELECT g.name AS genre,
|
|---|
| 44 | COUNT(t.ticket_id) AS total_tickets,
|
|---|
| 45 | SUM(t.price) AS total_revenue
|
|---|
| 46 | FROM GENRE g
|
|---|
| 47 | JOIN MOVIE_GENRE mg ON mg.genre_id = g.genre_id
|
|---|
| 48 | JOIN SCREENING s ON s.movie_id = mg.movie_id
|
|---|
| 49 | JOIN TICKET t ON t.screening_id = s.screening_id
|
|---|
| 50 | GROUP BY g.name
|
|---|
| 51 | ORDER BY total_tickets DESC;
|
|---|
| 52 |
|
|---|
| 53 | -- 3. Najaktivni periodi po mesec
|
|---|
| 54 | CREATE MATERIALIZED VIEW mat_busiest_months AS
|
|---|
| 55 | SELECT EXTRACT(YEAR FROM s.date)::int AS year,
|
|---|
| 56 | EXTRACT(MONTH FROM s.date)::int AS month,
|
|---|
| 57 | COUNT(t.ticket_id) AS total_tickets,
|
|---|
| 58 | SUM(t.price) AS total_revenue
|
|---|
| 59 | FROM SCREENING s
|
|---|
| 60 | JOIN TICKET t ON t.screening_id = s.screening_id
|
|---|
| 61 | GROUP BY year, month
|
|---|
| 62 | ORDER BY year, month;
|
|---|
| 63 |
|
|---|
| 64 | -- 4. Priod po kino
|
|---|
| 65 | CREATE MATERIALIZED VIEW mat_cinema_revenue AS
|
|---|
| 66 | SELECT c.name AS cinema,
|
|---|
| 67 | ci.name AS city,
|
|---|
| 68 | COUNT(t.ticket_id) AS total_tickets,
|
|---|
| 69 | SUM(t.price) AS total_revenue,
|
|---|
| 70 | ROUND(AVG(t.price)::numeric, 2) AS avg_ticket_price
|
|---|
| 71 | FROM CINEMA c
|
|---|
| 72 | JOIN CITY ci ON ci.city_id = c.city_id
|
|---|
| 73 | JOIN CINEMA_HALL ch ON ch.cinema_id = c.cinema_id
|
|---|
| 74 | JOIN SCREENING s ON s.cinemahall_id = ch.cinemahall_id
|
|---|
| 75 | JOIN TICKET t ON t.screening_id = s.screening_id
|
|---|
| 76 | GROUP BY c.name, ci.name
|
|---|
| 77 | ORDER BY total_revenue DESC;
|
|---|
| 78 |
|
|---|
| 79 | -- 5. Popolnetost na sali (bez COUNT DISTINCT)
|
|---|
| 80 | CREATE MATERIALIZED VIEW mat_hall_occupancy AS
|
|---|
| 81 | SELECT ch.description AS hall,
|
|---|
| 82 | c.name AS cinema,
|
|---|
| 83 | ch.capacity,
|
|---|
| 84 | COUNT(t.ticket_id) AS total_tickets_sold
|
|---|
| 85 | FROM CINEMA_HALL ch
|
|---|
| 86 | JOIN CINEMA c ON c.cinema_id = ch.cinema_id
|
|---|
| 87 | JOIN SCREENING s ON s.cinemahall_id = ch.cinemahall_id
|
|---|
| 88 | JOIN TICKET t ON t.screening_id = s.screening_id
|
|---|
| 89 | GROUP BY ch.description, c.name, ch.capacity
|
|---|
| 90 | ORDER BY total_tickets_sold DESC;
|
|---|
| 91 |
|
|---|
| 92 | -- 6. Najprodavani proizvodi
|
|---|
| 93 | CREATE MATERIALIZED VIEW mat_top_products AS
|
|---|
| 94 | SELECT p.name AS product,
|
|---|
| 95 | p.unit,
|
|---|
| 96 | p.price AS unit_price,
|
|---|
| 97 | SUM(pp.numbers) AS total_quantity_sold,
|
|---|
| 98 | SUM(pp.numbers * p.price) AS total_revenue
|
|---|
| 99 | FROM PRODUCT p
|
|---|
| 100 | JOIN PURCHASED_PRODUCT pp ON pp.product_id = p.product_id
|
|---|
| 101 | GROUP BY p.name, p.unit, p.price
|
|---|
| 102 | ORDER BY total_quantity_sold DESC;
|
|---|
| 103 |
|
|---|
| 104 | -- 7. Promocii vs priod
|
|---|
| 105 | CREATE MATERIALIZED VIEW mat_promotion_impact AS
|
|---|
| 106 | SELECT pr.name AS promotion,
|
|---|
| 107 | pr.discount AS discount_percent,
|
|---|
| 108 | COUNT(t.ticket_id) AS total_tickets,
|
|---|
| 109 | SUM(t.price) AS revenue_with_promotion,
|
|---|
| 110 | ROUND(AVG(t.price)::numeric, 2) AS avg_ticket_price
|
|---|
| 111 | FROM PROMOTION pr
|
|---|
| 112 | JOIN SCREENING s ON s.screening_id = pr.screening_id
|
|---|
| 113 | JOIN TICKET t ON t.screening_id = s.screening_id
|
|---|
| 114 | GROUP BY pr.name, pr.discount
|
|---|
| 115 | ORDER BY total_tickets DESC;
|
|---|
| 116 |
|
|---|
| 117 | -- 8. Rezervacii po status
|
|---|
| 118 | CREATE MATERIALIZED VIEW mat_reservation_status AS
|
|---|
| 119 | SELECT status,
|
|---|
| 120 | COUNT(*) AS total_reservations,
|
|---|
| 121 | ROUND(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER (), 2) AS percentage
|
|---|
| 122 | FROM RESERVATION
|
|---|
| 123 | GROUP BY status
|
|---|
| 124 | ORDER BY total_reservations DESC;
|
|---|
| 125 |
|
|---|
| 126 | -- 9. Popularni termini
|
|---|
| 127 | CREATE MATERIALIZED VIEW mat_popular_time_slots AS
|
|---|
| 128 | SELECT s.time AS time_slot,
|
|---|
| 129 | CASE
|
|---|
| 130 | WHEN s.time < '13:00:00' THEN 'Morning'
|
|---|
| 131 | WHEN s.time < '18:00:00' THEN 'Afternoon'
|
|---|
| 132 | ELSE 'Evening'
|
|---|
| 133 | END AS period,
|
|---|
| 134 | COUNT(t.ticket_id) AS total_tickets,
|
|---|
| 135 | SUM(t.price) AS total_revenue,
|
|---|
| 136 | ROUND(AVG(t.price)::numeric, 2) AS avg_ticket_price
|
|---|
| 137 | FROM SCREENING s
|
|---|
| 138 | JOIN TICKET t ON t.screening_id = s.screening_id
|
|---|
| 139 | GROUP BY s.time
|
|---|
| 140 | ORDER BY total_tickets DESC;
|
|---|
| 141 |
|
|---|
| 142 | -- 10. Proizvodi vs tiketi priod
|
|---|
| 143 | CREATE MATERIALIZED VIEW mat_product_vs_ticket_revenue AS
|
|---|
| 144 | SELECT 'Tickets' AS revenue_source, SUM(t.price) AS total_revenue
|
|---|
| 145 | FROM TICKET t
|
|---|
| 146 | UNION ALL
|
|---|
| 147 | SELECT 'Products', SUM(pp.numbers * p.price)
|
|---|
| 148 | FROM PURCHASED_PRODUCT pp
|
|---|
| 149 | JOIN PRODUCT p ON p.product_id = pp.product_id;
|
|---|
| 150 |
|
|---|
| 151 | -- 11. Utro vs Vecer priod
|
|---|
| 152 | CREATE MATERIALIZED VIEW mat_morning_vs_evening AS
|
|---|
| 153 | SELECT
|
|---|
| 154 | CASE
|
|---|
| 155 | WHEN s.time < '13:00:00' THEN 'Morning'
|
|---|
| 156 | WHEN s.time < '18:00:00' THEN 'Afternoon'
|
|---|
| 157 | ELSE 'Evening'
|
|---|
| 158 | END AS period,
|
|---|
| 159 | COUNT(t.ticket_id) AS total_tickets,
|
|---|
| 160 | SUM(t.price) AS total_revenue,
|
|---|
| 161 | ROUND(AVG(t.price)::numeric, 2) AS avg_ticket_price
|
|---|
| 162 | FROM SCREENING s
|
|---|
| 163 | JOIN TICKET t ON t.screening_id = s.screening_id
|
|---|
| 164 | GROUP BY period
|
|---|
| 165 | ORDER BY total_revenue DESC;
|
|---|
| 166 |
|
|---|
| 167 | -- 12. Review statistika po film
|
|---|
| 168 | CREATE MATERIALIZED VIEW mat_movie_review_stats AS
|
|---|
| 169 | SELECT m.title,
|
|---|
| 170 | COUNT(r.review_id) AS total_reviews,
|
|---|
| 171 | ROUND(AVG(r.rating)::numeric,2) AS avg_rating,
|
|---|
| 172 | MAX(r.rating) AS max_rating,
|
|---|
| 173 | MIN(r.rating) AS min_rating
|
|---|
| 174 | FROM MOVIE m
|
|---|
| 175 | JOIN REVIEW r ON r.movie_id = m.movie_id
|
|---|
| 176 | GROUP BY m.title
|
|---|
| 177 | ORDER BY avg_rating DESC;
|
|---|
| 178 |
|
|---|
| 179 | -- 13. Review statistika po zanr
|
|---|
| 180 | CREATE MATERIALIZED VIEW mat_genre_review_stats AS
|
|---|
| 181 | SELECT g.name AS genre,
|
|---|
| 182 | COUNT(r.review_id) AS total_reviews,
|
|---|
| 183 | ROUND(AVG(r.rating)::numeric,2) AS avg_rating
|
|---|
| 184 | FROM GENRE g
|
|---|
| 185 | JOIN MOVIE_GENRE mg ON mg.genre_id = g.genre_id
|
|---|
| 186 | JOIN REVIEW r ON r.movie_id = mg.movie_id
|
|---|
| 187 | GROUP BY g.name
|
|---|
| 188 | ORDER BY avg_rating DESC;
|
|---|
| 189 |
|
|---|
| 190 | --------------------------------
|
|---|
| 191 |
|
|---|
| 192 | --------------------------------
|
|---|
| 193 | DO $$
|
|---|
| 194 | DECLARE
|
|---|
| 195 | start_time TIMESTAMPTZ;
|
|---|
| 196 | end_time TIMESTAMPTZ;
|
|---|
| 197 | BEGIN
|
|---|
| 198 | -- 1
|
|---|
| 199 | start_time := clock_timestamp();
|
|---|
| 200 | PERFORM * FROM mat_movie_revenue;
|
|---|
| 201 | RAISE NOTICE 'mat_movie_revenue: % ms', EXTRACT(MILLISECONDS FROM clock_timestamp()-start_time);
|
|---|
| 202 |
|
|---|
| 203 | -- 2
|
|---|
| 204 | start_time := clock_timestamp();
|
|---|
| 205 | PERFORM * FROM mat_most_watched_genre;
|
|---|
| 206 | RAISE NOTICE 'mat_most_watched_genre: % ms', EXTRACT(MILLISECONDS FROM clock_timestamp()-start_time);
|
|---|
| 207 |
|
|---|
| 208 | -- 3
|
|---|
| 209 | start_time := clock_timestamp();
|
|---|
| 210 | PERFORM * FROM mat_busiest_months;
|
|---|
| 211 | RAISE NOTICE 'mat_busiest_months: % ms', EXTRACT(MILLISECONDS FROM clock_timestamp()-start_time);
|
|---|
| 212 |
|
|---|
| 213 | -- 4
|
|---|
| 214 | start_time := clock_timestamp();
|
|---|
| 215 | PERFORM * FROM mat_cinema_revenue;
|
|---|
| 216 | RAISE NOTICE 'mat_cinema_revenue: % ms', EXTRACT(MILLISECONDS FROM clock_timestamp()-start_time);
|
|---|
| 217 |
|
|---|
| 218 | -- 5
|
|---|
| 219 | start_time := clock_timestamp();
|
|---|
| 220 | PERFORM * FROM mat_hall_occupancy;
|
|---|
| 221 | RAISE NOTICE 'mat_hall_occupancy: % ms', EXTRACT(MILLISECONDS FROM clock_timestamp()-start_time);
|
|---|
| 222 |
|
|---|
| 223 | -- 6
|
|---|
| 224 | start_time := clock_timestamp();
|
|---|
| 225 | PERFORM * FROM mat_top_products;
|
|---|
| 226 | RAISE NOTICE 'mat_top_products: % ms', EXTRACT(MILLISECONDS FROM clock_timestamp()-start_time);
|
|---|
| 227 |
|
|---|
| 228 | -- 7
|
|---|
| 229 | start_time := clock_timestamp();
|
|---|
| 230 | PERFORM * FROM mat_promotion_impact;
|
|---|
| 231 | RAISE NOTICE 'mat_promotion_impact: % ms', EXTRACT(MILLISECONDS FROM clock_timestamp()-start_time);
|
|---|
| 232 |
|
|---|
| 233 | -- 8
|
|---|
| 234 | start_time := clock_timestamp();
|
|---|
| 235 | PERFORM * FROM mat_reservation_status;
|
|---|
| 236 | RAISE NOTICE 'mat_reservation_status: % ms', EXTRACT(MILLISECONDS FROM clock_timestamp()-start_time);
|
|---|
| 237 |
|
|---|
| 238 | -- 9
|
|---|
| 239 | start_time := clock_timestamp();
|
|---|
| 240 | PERFORM * FROM mat_popular_time_slots;
|
|---|
| 241 | RAISE NOTICE 'mat_popular_time_slots: % ms', EXTRACT(MILLISECONDS FROM clock_timestamp()-start_time);
|
|---|
| 242 |
|
|---|
| 243 | -- 10
|
|---|
| 244 | start_time := clock_timestamp();
|
|---|
| 245 | PERFORM * FROM mat_product_vs_ticket_revenue;
|
|---|
| 246 | RAISE NOTICE 'mat_product_vs_ticket_revenue: % ms', EXTRACT(MILLISECONDS FROM clock_timestamp()-start_time);
|
|---|
| 247 |
|
|---|
| 248 | -- 11
|
|---|
| 249 | start_time := clock_timestamp();
|
|---|
| 250 | PERFORM * FROM mat_morning_vs_evening;
|
|---|
| 251 | RAISE NOTICE 'mat_morning_vs_evening: % ms', EXTRACT(MILLISECONDS FROM clock_timestamp()-start_time);
|
|---|
| 252 |
|
|---|
| 253 | -- 12
|
|---|
| 254 | start_time := clock_timestamp();
|
|---|
| 255 | PERFORM * FROM mat_movie_review_stats;
|
|---|
| 256 | RAISE NOTICE 'mat_movie_review_stats: % ms', EXTRACT(MILLISECONDS FROM clock_timestamp()-start_time);
|
|---|
| 257 |
|
|---|
| 258 | -- 13
|
|---|
| 259 | start_time := clock_timestamp();
|
|---|
| 260 | PERFORM * FROM mat_genre_review_stats;
|
|---|
| 261 | RAISE NOTICE 'mat_genre_review_stats: % ms', EXTRACT(MILLISECONDS FROM clock_timestamp()-start_time);
|
|---|
| 262 | END $$; |
|---|