DatabaseProgramming: MajStore_Triggers_Functions_Procedures.sql

File MajStore_Triggers_Functions_Procedures.sql, 12.0 KB (added by 231049, 8 days ago)
Line 
1-- 1
2create or replace function fn_insert_premium_worker()
3 returns trigger
4 language plpgsql
5as $$
6 declare completed_status_id int;
7begin
8 select status_id
9 into completed_status_id
10 from Payment_Status
11 where status_name = 'Completed';
12
13 if new.payment_status = completed_status_id then
14 insert into Premium_Worker (start_date,end_date,plan_id,worker_id,payment_id)
15 select
16 new.payment_date,
17 new.payment_date + interval '1 day' * pp.duration_days,
18 new.plan_id,
19 wm.worker_id,
20 new.payment_id
21 from Worker_Method wm
22 join Premium_Plan pp
23 on pp.plan_id = new.plan_id
24 where wm.worker_method_id = new.worker_method_id;
25 end if;
26 return new;
27end;
28$$;
29
30create trigger trg_insert_premium_worker
31after insert or update on Payment
32for each row
33execute function fn_insert_premium_worker();
34
35--test
36insert into payment(amount, payment_date, worker_method_id, payment_status, plan_id)
37values (100, now(), 1, 2, 1);
38
39select * from premium_worker order by premium_id desc limit 3;
40
41
42
43
44
45
46-- 2
47create or replace function fn_is_worker_premium(p_worker_id int)
48 returns boolean
49 language plpgsql
50as $$
51 declare v_exists boolean;
52begin
53 select exists (
54 select 1
55 from premium_worker pw
56 where pw.worker_id = p_worker_id
57 and now() between pw.start_date and pw.end_date
58 )
59 into v_exists;
60
61 return v_exists;
62end;
63$$;
64
65-- test: true
66insert into premium_worker(start_date,end_date,plan_id,worker_id,payment_id)
67values (now() - interval '1 day',now() + interval '30 days',1,6630361,1);
68
69select fn_is_worker_premium(6630361);
70
71-- test: false
72insert into premium_worker(start_date,end_date,plan_id,worker_id,payment_id)
73values (now() - interval '30 days',now() - interval '1 day',1,6630362,1);
74
75select fn_is_worker_premium(6630362);
76
77
78
79
80
81
82-- 3
83create or replace function fn_notify_worker_premium_start()
84 returns trigger
85 language plpgsql
86as $$
87 declare v_user_id int; v_plan_name text;
88begin
89 select w.user_id
90 into v_user_id
91 from worker w
92 where w.worker_id = new.worker_id;
93
94 select pp.name
95 into v_plan_name
96 from premium_plan pp
97 where pp.plan_id = new.plan_id;
98
99 insert into notification(message, is_read, created_at, user_id)
100 values ('Your Premium subscription (' || v_plan_name || ') is now active until ' || to_char(new.end_date, 'DD Mon YYYY'),false,now(),v_user_id);
101
102 return new;
103end;
104$$;
105
106create trigger trg_notify_worker_premium_start
107 after insert on premium_worker
108 for each row
109execute function fn_notify_worker_premium_start();
110
111
112--test
113insert into premium_worker(start_date, end_date, plan_id, worker_id, payment_id)
114values (now(), now() + interval '30 days', 1, 6630361, 1);
115
116select * from notification
117where user_id = (select user_id from worker where worker_id = 6630361)
118order by created_at desc
119limit 5;
120
121
122
123
124
125
126-- 4
127create or replace function fn_prevent_review_without_hire()
128 returns trigger
129 language plpgsql
130as $$
131 declare v_worker_id int;
132begin
133 select ws.worker_id
134 into v_worker_id
135 from worker_specialty ws
136 where ws.worker_specialty_id = new.worker_specialty_id;
137
138 if v_worker_id is null then
139 raise exception 'Worker_Specialty % not found.', new.worker_specialty_id;
140 end if;
141
142 if not exists (
143 select 1
144 from application a
145 join application_status s on a.status_id = s.status_id
146 join post p on a.post_id = p.post_id
147 join post_specialty ps on ps.post_id = p.post_id
148 join worker_specialty ws on ws.worker_specialty_id = new.worker_specialty_id
149 where a.worker_id = v_worker_id
150 and p.user_id = new.reviewer_id
151 and s.status_name = 'Accepted'
152 and ps.specialty_id = ws.specialty_id
153 ) then
154 raise exception 'User % has not hired worker % for this specialty, and cannot review them.', new.reviewer_id, v_worker_id;
155 end if;
156
157 return new;
158end;
159$$;
160
161create trigger trg_prevent_review_without_hire
162 before insert on Review
163 for each row
164execute function fn_prevent_review_without_hire();
165
166--test should fail
167insert into review(grade, created_at, reviewer_id, worker_specialty_id)
168values (5, '2026-05-14 12:00:00.000', 218486, 1);
169
170--test should pass
171insert into review(grade, created_at, reviewer_id, worker_specialty_id)
172values (5, '2026-05-14 12:00:00.000', 366799, 2);
173
174
175
176
177
178
179
180
181-- 5
182create or replace function block_application_to_closed_post()
183 returns trigger
184 language plpgsql
185as $$
186 declare v_status_name text;
187begin
188 select ps.status_name
189 into v_status_name
190 from post p
191 join post_status ps on p.status_id = ps.status_id
192 where p.post_id = new.post_id;
193
194 if v_status_name is null
195 then raise exception 'Post % does not exist.', new.post_id;
196 end if;
197
198 if v_status_name <> 'Active' then
199 raise exception 'Cannot apply to post %: status is "%", only "Active" posts accept applications.', new.post_id, v_status_name;
200 end if;
201
202 return new;
203end;
204$$;
205
206create trigger trg_block_application_to_closed_post
207before insert on application
208for each row execute function block_application_to_closed_post();
209
210-- test
211insert into Application(message,needed_time,expected_price,created_at,worker_id,post_id,status_id)
212values('I need work','09:00:00',200,'2025-05-06 17:36:15.015',6630361,11,1);
213
214
215
216
217
218
219-- 6
220create or replace function prevent_duplicate_application()
221 returns trigger
222 language plpgsql
223as $$
224begin
225 if exists (
226 select 1
227 from application a
228 join application_status s on a.status_id = s.status_id
229 where a.worker_id = new.worker_id
230 and a.post_id = new.post_id
231 and s.status_name not in ('Cancelled')
232 ) then
233 raise exception 'Worker % already has an application for post %.', new.worker_id, new.post_id;
234 end if;
235
236 return new;
237end;
238$$;
239
240create trigger trg_prevent_duplicate_application
241before insert on application
242for each row execute function prevent_duplicate_application();
243
244-- test
245insert into Application(message,needed_time,expected_price,created_at,worker_id,post_id,status_id)
246values('I need work','09:00:00',200,'2025-05-06 17:36:15.015',6630361,9,1);
247
248
249
250
251
252
253-- 7
254create or replace function fn_auto_create_calendar()
255 returns trigger
256 language plpgsql
257as $$
258 declare v_worker_id int;
259begin
260 v_worker_id := new.worker_id;
261
262 insert into calendar(worker_id)
263 values (v_worker_id);
264
265 return new;
266end;
267$$;
268
269create trigger trg_auto_create_calendar
270after insert on worker
271for each row execute function fn_auto_create_calendar();
272
273--test
274insert into worker(bio, works_remote, user_id, location_id)
275values ('Experienced electrician', true, 70728, 1);
276
277select * from calendar where worker_id = (select max(worker_id) from worker);
278select * from worker where worker_id = 6772445;
279
280
281
282
283
284
285-- 8
286create or replace function fn_auto_create_worker_notification()
287 returns trigger
288 language plpgsql
289as $$
290 declare
291 v_worker_user_id int;
292 v_status_name text;
293begin
294 select s.status_name
295 into v_status_name
296 from application_status s
297 where s.status_id = new.status_id;
298
299 if v_status_name in ('Accepted', 'Rejected', 'Deleted') then
300 select w.user_id
301 into v_worker_user_id
302 from worker w
303 where w.worker_id = new.worker_id;
304
305 insert into notification(message, is_read, created_at, user_id)
306 values (
307 'Your application has been ' || v_status_name,
308 false,
309 now(),
310 v_worker_user_id
311 );
312 end if;
313
314 return new;
315end;
316$$;
317
318create trigger trg_auto_create_worker_notification
319after update on application
320for each row execute function fn_auto_create_worker_notification()
321
322
323--test
324update application
325set status_id = 2
326where application_id = 22279;
327
328select * from notification
329where user_id = (select w.user_id from worker w where w.worker_id = 6746074)
330order by created_at desc
331limit 5;
332
333
334
335
336
337
338-- 9
339create or replace procedure sp_reject_pending_applications(p_post_id int)
340 language plpgsql
341as $$
342declare
343 v_rejected_status_id int;
344 v_completed_post_status_id int;
345 v_current_post_status text;
346begin
347 select ps.status_name
348 into v_current_post_status
349 from post p join post_status ps on ps.status_id = p.status_id
350 where p.post_id = p_post_id;
351
352 if v_current_post_status is null then
353 raise exception 'Post % does not exist.', p_post_id;
354 end if;
355
356 if v_current_post_status <> 'Active' then
357 raise exception 'Post % is not active, current status is "%".', p_post_id, v_current_post_status;
358 end if;
359
360 select status_id
361 into v_completed_post_status_id
362 from post_status
363 where status_name = 'Completed';
364
365 update post
366 set status_id = v_completed_post_status_id
367 where post_id = p_post_id;
368
369 select status_id
370 into v_rejected_status_id
371 from application_status
372 where status_name = 'Rejected';
373
374 update application
375 set status_id = v_rejected_status_id
376 where post_id = p_post_id
377 and status_id not in (
378 select status_id from application_status
379 where status_name in ('Accepted', 'Deleted')
380 );
381end;
382$$;
383
384-- test
385call sp_reject_pending_applications(19);
386
387select ps.status_name from post p
388join post_status ps on ps.status_id = p.status_id
389where p.post_id = 19;
390
391select a.application_id, s.status_name
392from application a
393join application_status s on s.status_id = a.status_id
394where a.post_id = 19;
395
396
397
398
399
400
401
402-- 10
403create or replace function fn_notify_client_new_application()
404 returns trigger
405 language plpgsql
406as $$
407 declare
408 v_client_user_id int;
409 v_post_title text;
410 v_worker_name text;
411begin
412 select p.user_id, p.title
413 into v_client_user_id, v_post_title
414 from post p
415 where p.post_id = new.post_id;
416
417 select u.first_name || ' ' || u.last_name
418 into v_worker_name
419 from worker w
420 join "User" u on u.user_id = w.user_id
421 where w.worker_id = new.worker_id;
422
423 insert into notification(message, is_read, created_at, user_id)
424 values (
425 'Worker ' || v_worker_name || ' has applied to your post "' || v_post_title || '"',
426 false,
427 now(),
428 v_client_user_id
429 );
430
431 return new;
432end;
433$$;
434
435create trigger trg_notify_client_new_application
436after insert on application
437for each row execute function fn_notify_client_new_application();
438
439-- test
440insert into application(message, needed_time, expected_price, created_at, worker_id, post_id, status_id)
441values ('I can do the job', '02:00:00', 150.00, '2026-05-14 12:00:00.000', 6630372, 166254, 1);
442
443select * from notification
444where user_id = (select user_id from post where post_id = 166254)
445order by created_at desc
446limit 5;
447
448
449
450
451
452
453
454
455
456-- 11
457create or replace function fn_check_worker_specialty_for_post()
458 returns trigger
459 language plpgsql
460as $$
461 declare v_has_specialty bool;
462begin
463 select exists (
464 select 1
465 from worker_specialty ws
466 join post_specialty ps on ps.specialty_id = ws.specialty_id
467 where ws.worker_id = new.worker_id
468 and ps.post_id = new.post_id
469 )
470 into v_has_specialty;
471
472 if not v_has_specialty then
473 raise exception
474 'Worker % does not have any of the required specialties for post %.', new.worker_id, new.post_id;
475 end if;
476
477 return new;
478end;
479$$;
480
481create trigger trg_check_worker_specialty_for_post
482before insert on application
483for each row execute function fn_check_worker_specialty_for_post();
484
485-- test
486insert into application(message, needed_time, expected_price, created_at, worker_id, post_id, status_id)
487values ('I can do the job', '02:00:00', 150.00, '2026-05-14 12:00:00.000', 6630357, 166252, 1);