DatabaseCreation: views.sql

File views.sql, 9.5 KB (added by 231133, 7 days ago)
Line 
1-- 1. Event sales summary
2-- Used by organisers/admin dashboard.
3CREATE OR REPLACE VIEW public.v_event_sales_summary AS
4SELECT
5 e.event_id,
6 e.title AS event_title,
7 o.organiser_id,
8 o.company_name AS organiser_name,
9 COUNT(t.ticket_id) AS tickets_sold,
10 COUNT(DISTINCT oc.order_id) AS total_orders,
11 COALESCE(SUM(p.amount_paid), 0) AS total_revenue,
12 ROUND(AVG(p.amount_paid), 2) AS average_payment_amount,
13 MIN(oc.created_at) AS first_order_at,
14 MAX(oc.created_at) AS last_order_at
15FROM public.event e
16 JOIN public.organiser o
17 ON o.organiser_id = e.organiser_id
18 JOIN public.ticket_type tt
19 ON tt.event_id = e.event_id
20 JOIN public.ticket t
21 ON t.ticket_type_id = tt.ticket_type_id
22 JOIN public.order_cart oc
23 ON oc.order_id = t.order_id
24 LEFT JOIN public.payment p
25 ON p.order_id = oc.order_id
26GROUP BY
27 e.event_id,
28 e.title,
29 o.organiser_id,
30 o.company_name;
31
32select *
33from v_event_sales_summary;
34
35-- 2. User purchase profile
36-- Used for user account page / CRM / recommendations.
37CREATE OR REPLACE VIEW public.v_user_purchase_profile AS
38SELECT
39 u.user_id,
40 u.username,
41 u.email,
42 COUNT(DISTINCT oc.order_id) AS total_orders,
43 COUNT(t.ticket_id) AS total_tickets,
44 COALESCE(SUM(p.amount_paid), 0) AS total_spent,
45 ROUND(AVG(p.amount_paid), 2) AS average_order_payment,
46 MIN(oc.created_at) AS first_purchase_at,
47 MAX(oc.created_at) AS last_purchase_at
48FROM public.user_app u
49 LEFT JOIN public.order_cart oc
50 ON oc.user_id = u.user_id
51 LEFT JOIN public.ticket t
52 ON t.order_id = oc.order_id
53 LEFT JOIN public.payment p
54 ON p.order_id = oc.order_id
55GROUP BY
56 u.user_id,
57 u.username,
58 u.email;
59
60select *
61from v_user_purchase_profile;
62
63-- 3. Ticket scan statistics per event
64-- Used by event check-in dashboard.
65CREATE OR REPLACE VIEW public.v_event_checkin_statistics AS
66SELECT
67 e.event_id,
68 e.title AS event_title,
69 COUNT(t.ticket_id) AS total_tickets,
70 COUNT(*) FILTER (WHERE t.is_scanned = true) AS scanned_tickets,
71 COUNT(*) FILTER (WHERE t.is_scanned = false) AS unscanned_tickets,
72 ROUND(
73 100.0 * COUNT(*) FILTER (WHERE t.is_scanned = true)
74 / NULLIF(COUNT(t.ticket_id), 0),
75 2
76 ) AS scanned_percentage,
77 MIN(t.scanned_at) FILTER (WHERE t.is_scanned = true) AS first_scan_at,
78 MAX(t.scanned_at) FILTER (WHERE t.is_scanned = true) AS last_scan_at
79FROM public.event e
80 JOIN public.ticket_type tt
81 ON tt.event_id = e.event_id
82 JOIN public.ticket t
83 ON t.ticket_type_id = tt.ticket_type_id
84GROUP BY
85 e.event_id,
86 e.title;
87
88select *
89from v_event_checkin_statistics;
90
91-- 4. Session occupancy and waitlist pressure
92-- Used to see overloaded sessions.
93CREATE OR REPLACE VIEW public.v_session_demand_overview AS
94SELECT
95 ess.schedule_id,
96 ess.session_title,
97 e.event_id,
98 e.title AS event_title,
99 l.name AS location_name,
100 s.section_name,
101 s.capacity AS section_capacity,
102 COUNT(DISTINCT w.waitlist_id) AS waitlist_entries,
103 COUNT(DISTINCT w.waitlist_id) FILTER (WHERE w.status = 'WAITING') AS active_waitlist_entries,
104 ROUND(
105 COUNT(DISTINCT w.waitlist_id)::numeric
106 / NULLIF(s.capacity, 0),
107 4
108 ) AS waitlist_to_capacity_ratio
109FROM public.event_schedule_session ess
110 JOIN public.event e
111 ON e.event_id = ess.event_id
112 JOIN public.section s
113 ON s.section_id = ess.section_id
114 JOIN public.location l
115 ON l.location_id = s.location_id
116 LEFT JOIN public.waitlist_entry w
117 ON w.event_schedule_session_id = ess.schedule_id
118GROUP BY
119 ess.schedule_id,
120 ess.session_title,
121 e.event_id,
122 e.title,
123 l.name,
124 s.section_name,
125 s.capacity;
126
127select *
128from v_session_demand_overview;
129
130-- 5. Event rating summary
131-- Used on public event pages.
132CREATE OR REPLACE VIEW public.v_event_rating_summary AS
133SELECT
134 e.event_id,
135 e.title AS event_title,
136 COUNT(r.review_id) AS review_count,
137 ROUND(AVG(r.star_rating), 2) AS average_rating,
138 COUNT(*) FILTER (WHERE r.star_rating = 5) AS five_star_reviews,
139 COUNT(*) FILTER (WHERE r.star_rating = 4) AS four_star_reviews,
140 COUNT(*) FILTER (WHERE r.star_rating <= 2) AS negative_reviews,
141 MAX(r.created_at) AS latest_review_at
142FROM public.event e
143 LEFT JOIN public.review r
144 ON r.event_id = e.event_id
145GROUP BY
146 e.event_id,
147 e.title;
148
149select *
150from v_event_rating_summary
151order by event_id;
152
153-- 6. Organiser performance dashboard
154-- Used internally by platform admins.
155CREATE OR REPLACE VIEW public.v_organiser_performance_dashboard AS
156SELECT
157 o.organiser_id,
158 o.company_name AS organiser_name,
159 COUNT(DISTINCT e.event_id) AS total_events,
160 COUNT(DISTINCT t.ticket_id) AS total_tickets_sold,
161 COUNT(DISTINCT oc.order_id) AS total_orders,
162 COALESCE(SUM(p.amount_paid), 0) AS total_revenue,
163 ROUND(AVG(r.star_rating), 2) AS average_event_rating,
164 COUNT(DISTINCT r.review_id) AS total_reviews
165FROM public.organiser o
166 LEFT JOIN public.event e
167 ON e.organiser_id = o.organiser_id
168 LEFT JOIN public.ticket_type tt
169 ON tt.event_id = e.event_id
170 LEFT JOIN public.ticket t
171 ON t.ticket_type_id = tt.ticket_type_id
172 LEFT JOIN public.order_cart oc
173 ON oc.order_id = t.order_id
174 LEFT JOIN public.payment p
175 ON p.order_id = oc.order_id
176 LEFT JOIN public.review r
177 ON r.event_id = e.event_id
178GROUP BY
179 o.organiser_id,
180 o.company_name;
181
182select *
183from v_organiser_performance_dashboard;
184
185-- 7. Location utilization summary
186-- Used by venue/location managers.
187CREATE OR REPLACE VIEW public.v_location_utilization_summary AS
188SELECT
189 l.location_id,
190 l.name AS location_name,
191 lt.type_name AS location_type,
192 COUNT(DISTINCT s.section_id) AS total_sections,
193 COUNT(DISTINCT seat.seat_id) AS total_seats,
194 COUNT(DISTINCT ess.schedule_id) AS scheduled_sessions,
195 COUNT(DISTINCT e.event_id) AS hosted_events,
196 COUNT(DISTINCT seat.seat_id) FILTER (WHERE seat.is_accessible = true) AS accessible_seats,
197 COUNT(DISTINCT seat.seat_id) FILTER (WHERE seat.is_available = true) AS available_seats
198FROM public.location l
199 JOIN public.location_type lt
200 ON lt.type_id = l.type_id
201 LEFT JOIN public.section s
202 ON s.location_id = l.location_id
203 LEFT JOIN public.seat seat
204 ON seat.section_id = s.section_id
205 LEFT JOIN public.event_schedule_session ess
206 ON ess.section_id = s.section_id
207 LEFT JOIN public.event e
208 ON e.event_id = ess.event_id
209GROUP BY
210 l.location_id,
211 l.name,
212 lt.type_name;
213
214select *
215from v_location_utilization_summary;
216
217-- 8. Refund analysis
218-- Used by finance/support team.
219CREATE OR REPLACE VIEW public.v_refund_analysis AS
220SELECT
221 rr.refund_request_id,
222 rr.requested_at,
223 rr.accepted_at,
224 CASE
225 WHEN rr.accepted_at IS NOT NULL THEN 'ACCEPTED'
226 ELSE 'PENDING'
227 END AS refund_status,
228 u.user_id,
229 u.username,
230 oc.order_id,
231 p.payment_id,
232 p.amount_paid,
233 p.method_id,
234 pm.method_name,
235 rr.reason
236FROM public.refund_request rr
237 JOIN public.user_app u
238 ON u.user_id = rr.user_id
239 JOIN public.payment p
240 ON p.payment_id = rr.payment_id
241 JOIN public.payment_method pm
242 ON pm.method_id = p.method_id
243 JOIN public.order_cart oc
244 ON oc.order_id = p.order_id;
245
246select *
247from v_refund_analysis;
248
249-- 9. Event full search/details view
250-- Used by public event browsing/search page.
251CREATE OR REPLACE VIEW public.v_event_public_details AS
252SELECT
253 e.event_id,
254 e.title AS event_title,
255 e.start_datetime,
256 e.end_datetime,
257 es.status_name AS event_status,
258 o.company_name AS organiser_name,
259
260 STRING_AGG(DISTINCT c.name, ', ') AS categories,
261
262 COUNT(DISTINCT ess.schedule_id) AS session_count,
263 COUNT(DISTINCT sp.sponsor_id) AS sponsor_count,
264 COUNT(DISTINCT r.review_id) AS review_count,
265 ROUND(AVG(r.star_rating), 2) AS average_rating,
266
267 MIN(pt.price) AS lowest_ticket_price,
268 MAX(pt.price) AS highest_ticket_price,
269
270 COUNT(DISTINCT t.ticket_id) AS tickets_sold
271FROM public.event e
272 JOIN public.event_status es
273 ON es.event_status_id = e.event_status_id
274 JOIN public.organiser o
275 ON o.organiser_id = e.organiser_id
276 LEFT JOIN public.event_category ec
277 ON ec.event_id = e.event_id
278 LEFT JOIN public.category c
279 ON c.id = ec.category_id
280 LEFT JOIN public.event_schedule_session ess
281 ON ess.event_id = e.event_id
282 LEFT JOIN public.sponsor_event se
283 ON se.event_id = e.event_id
284 LEFT JOIN public.sponsor sp
285 ON sp.sponsor_id = se.sponsor_id
286 LEFT JOIN public.review r
287 ON r.event_id = e.event_id
288 LEFT JOIN public.ticket_type tt
289 ON tt.event_id = e.event_id
290 LEFT JOIN public.price_tier pt
291 ON pt.ticket_type_id = tt.ticket_type_id
292 LEFT JOIN public.ticket t
293 ON t.ticket_type_id = tt.ticket_type_id
294GROUP BY
295 e.event_id,
296 e.title,
297 e.start_datetime,
298 e.end_datetime,
299 es.status_name,
300 o.company_name;
301
302select *
303from v_event_public_details;