DatabaseProgramming: console_12.sql

File console_12.sql, 9.4 KB (added by 231166, 5 days ago)
Line 
1--6 funkcii / 3 po covek
2--KIKO FUNKCII::
3--get_avg_rating(content_id) — vrakja prosecen rejting na film/serija
4
5CREATE FUNCTION get_avg_rating(p_content_id INT)
6RETURNS NUMERIC AS $$
7DECLARE
8 v_avg NUMERIC;
9BEGIN
10 SELECT ROUND(AVG(RatingValue), 2)
11 INTO v_avg
12 FROM Rating
13 WHERE ContentContentID = p_content_id;
14
15 RETURN v_avg;
16END;
17$$ LANGUAGE plpgsql;
18
19
20
21
22--get_user_watch_count(user_id) — vrakja kolku sodrzini gledal nekoj korisnik
23
24CREATE FUNCTION get_user_watch_count(p_user_id INT)
25RETURNS INT AS $$
26DECLARE
27 v_count INT;
28BEGIN
29 SELECT COUNT(*)
30 INTO v_count
31 FROM WatchHistory
32 WHERE UserUserID = p_user_id;
33
34 RETURN v_count;
35END;
36$$ LANGUAGE plpgsql;
37
38
39
40
41
42--get_content_genres(content_id) — gi vrakja site zhanri za nekoja sodrzina (deka se posebni tabeli, namesto da se prai join, da se dobie direkt sho zhanra e nekoj film/serija)
43
44CREATE FUNCTION get_content_genres(p_content_id INT)
45RETURNS VARCHAR AS $$
46DECLARE
47 v_genres VARCHAR;
48BEGIN
49 SELECT STRING_AGG(g.Name, ', ' ORDER BY g.Name)
50 INTO v_genres
51 FROM Genre g
52 JOIN Content_Genre cg ON cg.GenreGenreID = g.GenreID
53 WHERE cg.ContentContentID = p_content_id;
54
55 RETURN COALESCE(v_genres, 'No genres found');
56END;
57$$ LANGUAGE plpgsql;
58
59
60
61
62
63--Damjan FUNKCII:
64--get_subscription_info(user_id) — sto platil nekoj korisnik
65
66CREATE FUNCTION get_subscription_info(p_user_id INT)
67RETURNS TABLE(plan_name VARCHAR, price NUMERIC, max_devices INT, status VARCHAR) AS $$
68BEGIN
69 RETURN QUERY
70 SELECT
71 s.Name,
72 s.Price,
73 s.MaxDevices,
74 us.Status
75 FROM User_Subscription us
76 JOIN Subscription s ON s.SubscriptionID = us.SubscriptionSubscriptionID
77 WHERE us.UserUserID = p_user_id
78 LIMIT 1;
79END;
80$$ LANGUAGE plpgsql;
81
82
83
84
85
86
87--get_series_episode_count(series_id) — vkupen broj na epizodi za serija
88
89
90CREATE FUNCTION get_series_episode_count(p_series_id INT)
91RETURNS INT AS $$
92DECLARE
93 v_count INT;
94BEGIN
95 SELECT COUNT(e.EpisodeID)
96 INTO v_count
97 FROM Episode e
98 JOIN Season sea ON sea.SeasonID = e.SeasonSeasonID
99 WHERE sea.SeriesSeriesID = p_series_id;
100
101 RETURN v_count;
102END;
103$$ LANGUAGE plpgsql;
104
105
106
107
108
109
110--get_top_content_by_genre(genre_name) — vrati top sodrzina spored zhanra
111
112CREATE FUNCTION get_top_content_by_genre(p_genre_name VARCHAR)
113RETURNS TABLE(title VARCHAR, avg_rating NUMERIC, total_ratings BIGINT) AS $$
114BEGIN
115 RETURN QUERY
116 SELECT
117 m.title,
118 ROUND(AVG(r.RatingValue), 2) AS avg_rating,
119 COUNT(r.RatingID) AS total_ratings
120 FROM Media m
121 JOIN Content_Genre cg ON cg.ContentContentID = m.ContentID
122 JOIN Genre g ON g.GenreID = cg.GenreGenreID
123 JOIN Rating r ON r.ContentContentID = m.ContentID
124 WHERE g.Name = p_genre_name
125 GROUP BY m.title
126 ORDER BY avg_rating DESC
127 LIMIT 10;
128END;
129$$ LANGUAGE plpgsql;
130
131
132
133
134
135--KIKO TRIGERI
136
137--Trigger 1 — koga ke se izbrishe korisnik, da se logira vo nova tabela
138
139--ni trea nova tabela za ova:
140CREATE TABLE IF NOT EXISTS User_Delete_Log (
141 LogID SERIAL PRIMARY KEY,
142 UserID INT,
143 Username VARCHAR(255),
144 Email VARCHAR(255),
145 DeletedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP
146);
147
148
149--eve go trigerot:
150CREATE FUNCTION trg_log_user_delete()
151RETURNS TRIGGER AS $$
152BEGIN
153 INSERT INTO User_Delete_Log (UserID, Username, Email)
154 VALUES (OLD.UserID, OLD.Username, OLD.Email);
155 RETURN OLD;
156END;
157$$ LANGUAGE plpgsql;
158
159CREATE TRIGGER trigger_log_user_delete
160BEFORE DELETE ON "User"
161FOR EACH ROW
162EXECUTE FUNCTION trg_log_user_delete();
163
164
165--za da testiram deletnav user: DELETE FROM "User" WHERE UserID = 159089;
166--za proverka deka stvarno e vo novata tabela: SELECT * FROM User_Delete_Log;
167
168
169
170
171
172
173--Trigger 2 — koga ke se vnese rating, da se proveri dali e megju 1 i 10
174
175CREATE FUNCTION trg_validate_rating()
176RETURNS TRIGGER AS $$
177BEGIN
178 IF NEW.RatingValue < 1 OR NEW.RatingValue > 10 THEN
179 RAISE EXCEPTION 'RatingValue mora da bide pomegu 1 i 10, vnesena vrednost: %', NEW.RatingValue;
180 END IF;
181 RETURN NEW;
182END;
183$$ LANGUAGE plpgsql;
184
185CREATE TRIGGER trigger_validate_rating
186BEFORE INSERT OR UPDATE ON Rating
187FOR EACH ROW
188EXECUTE FUNCTION trg_validate_rating();
189
190--za proverka deka ke frli greska: INSERT INTO Rating (RatingValue, UserUserID, ContentContentID)
191--VALUES (15, 159090, 3);
192
193
194
195
196
197
198--Trigger 3 — koga ke se vnese nov watch history zapis, avtomatski da se azhurira na progress = 100 ako e pominato vremetraenjeto
199
200CREATE FUNCTION trg_auto_complete_progress()
201RETURNS TRIGGER AS $$
202DECLARE
203 v_duration INT;
204BEGIN
205 -- da se zeme traenjeto na watchable
206 SELECT duration INTO v_duration
207 FROM Watchable
208 WHERE WatchableID = NEW.WatchableWatchableID;
209
210 -- ako progress e 90% ili povekje, set na 100%
211 IF NEW.Progress_percentage >= 90 THEN
212 NEW.Progress_percentage := 100;
213 END IF;
214
215 RETURN NEW;
216END;
217$$ LANGUAGE plpgsql;
218
219CREATE TRIGGER trigger_auto_complete_progress
220BEFORE INSERT ON WatchHistory
221FOR EACH ROW
222EXECUTE FUNCTION trg_auto_complete_progress();
223
224--proverka:
225
226--vnesuvanje so progress 95. treba da stane 100
227
228--INSERT INTO WatchHistory (WatchedAt, Progress_percentage, UserUserID, ContentContentID, WatchableWatchableID)
229--VALUES (CURRENT_DATE, 95, 159090, 1, 1);
230
231
232--proverka za dali stanalo (vekje e izvrshena gornata sho znaci mozeme so ovaa samo da proverime na labot):
233
234--SELECT Progress_percentage FROM WatchHistory
235--WHERE UserUserID = 159090
236--ORDER BY HistoryID DESC
237--LIMIT 1;
238
239
240
241
242
243
244
245--Damjan TRIGERI:
246
247--TRIGGER 1 - koga end_date e pominat na subscription, avtomatski da se stavi status EXPIRED
248
249CREATE FUNCTION trg_auto_expire_subscription()
250RETURNS TRIGGER AS $$
251BEGIN
252 IF NEW.End_date IS NOT NULL AND NEW.End_date < CURRENT_DATE AND NEW.Status != 'Expired' THEN
253 NEW.Status := 'Expired';
254 END IF;
255 RETURN NEW;
256END;
257$$ LANGUAGE plpgsql;
258
259CREATE TRIGGER trigger_auto_expire_subscription
260BEFORE UPDATE ON User_Subscription
261FOR EACH ROW
262EXECUTE FUNCTION trg_auto_expire_subscription();
263
264--za da proveram smeniv end date na user subscription 3 za da vidam dali proraboti
265--UPDATE User_Subscription
266--SET End_date = '2026-05-01'
267--WHERE UserSubscriptionID = 3;
268
269--eve ja komandata za da se proveri dali stvarno se promeni samoto vo expired:
270--SELECT UserSubscriptionID, Start_date, End_date, Status
271--FROM User_Subscription
272--WHERE UserSubscriptionID = 3;
273
274
275
276
277
278
279
280
281
282--TRIGGER 2 - da se spreci premnogu uredi, odnosno koga ke se dodava nov ured, da se proveruva max_devices spored planot na subscriptionot
283
284CREATE FUNCTION trg_check_max_devices()
285RETURNS TRIGGER AS $$
286DECLARE
287 v_max_devices INT;
288 v_current_devices INT;
289BEGIN
290 -- maksimalniot broj na uredi od planot
291 SELECT s.MaxDevices INTO v_max_devices
292 FROM User_Subscription us
293 JOIN Subscription s ON s.SubscriptionID = us.SubscriptionSubscriptionID
294 WHERE us.UserSubscriptionID = NEW.UserSubscriptionID;
295
296 -- proverka za kolku uredi vekje ima
297 SELECT COUNT(*) INTO v_current_devices
298 FROM Devices
299 WHERE UserSubscriptionID = NEW.UserSubscriptionID;
300
301 IF v_current_devices >= v_max_devices THEN
302 RAISE EXCEPTION 'Maksimalen broj na uredi e dostигнат: % od %', v_current_devices, v_max_devices;
303 END IF;
304
305 RETURN NEW;
306END;
307$$ LANGUAGE plpgsql;
308
309CREATE TRIGGER trigger_check_max_devices
310BEFORE INSERT ON Devices
311FOR EACH ROW
312EXECUTE FUNCTION trg_check_max_devices();
313
314
315--probav so user subscription id 3 kade sto imase 0 uredi a maksimalno 1 ured.
316
317-- dodavanje prv ured pomina
318--INSERT INTO Devices (DeviceType, LastLogIn, UserSubscriptionID)
319--VALUES ('Mobile Phone', CURRENT_DATE, 3);
320
321-- dodavanje vtor ured ne pomina
322--INSERT INTO Devices (DeviceType, LastLogIn, UserSubscriptionID)
323--VALUES ('Tablet', CURRENT_DATE, 3);
324
325
326
327
328
329
330
331
332
333
334--TRIGGER 3 - log pri promena na status. koga user subscription ke smeni status, da se logira taa promena
335
336CREATE TABLE Subscription_Status_Log (
337 LogID SERIAL PRIMARY KEY,
338 UserSubID INT,
339 UserID INT,
340 OldStatus VARCHAR(255),
341 NewStatus VARCHAR(255),
342 ChangedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP
343);
344
345
346
347CREATE FUNCTION trg_log_subscription_status_change()
348RETURNS TRIGGER AS $$
349BEGIN
350 IF OLD.Status <> NEW.Status THEN
351 INSERT INTO Subscription_Status_Log (UserSubID, UserID, OldStatus, NewStatus)
352 VALUES (OLD.UserSubscriptionID, OLD.UserUserID, OLD.Status, NEW.Status);
353 END IF;
354 RETURN NEW;
355END;
356$$ LANGUAGE plpgsql;
357
358CREATE TRIGGER trigger_log_subscription_status_change
359AFTER UPDATE ON User_Subscription
360FOR EACH ROW
361EXECUTE FUNCTION trg_log_subscription_status_change();
362
363--testiranje:
364--promena na status:
365--UPDATE User_Subscription
366--SET Status = 'Cancelled'
367--WHERE UserSubscriptionID = (
368 --SELECT UserSubscriptionID FROM User_Subscription LIMIT 1
369--);
370
371--proverkata od tabelata:::: (za lab ova)
372--SELECT * FROM Subscription_Status_Log;
373
374
375
376
377
378
379
380
381
382
383--on the lowkey staiv indeksi na rating watch history i review deka se ogromni
384CREATE INDEX idx_rating_content ON Rating (ContentContentID);
385CREATE INDEX idx_rating_user ON Rating (UserUserID);
386CREATE INDEX idx_watchhistory_content ON WatchHistory (ContentContentID);
387CREATE INDEX idx_watchhistory_user ON WatchHistory (UserUserID);
388CREATE INDEX idx_review_content ON Review (ContentContentID);
389CREATE INDEX idx_review_user ON Review (UserUserID);
390
391--So dodavanje na indeksi na Rating tabelata, vremeto za izvrshuvanje na funkcija so taa tabela se namali od 1 cas na 1.7 minuti — 35x zabrzuvanje na 24 milioni zapisi
392
393
394
395