| | 1 | = Фаза 4 - Функции, процедури, тригери = |
| | 2 | |
| | 3 | == Функции == |
| | 4 | |
| | 5 | === get_avg_gpa_by_university === |
| | 6 | Пресметува просечна GPA на сите студенти запишани на факултети кои припаѓаат на даден универзитет. Се користи при генерирање на академски извештаи и споредба на успешноста на студентите по универзитет. |
| | 7 | {{{ |
| | 8 | CREATE OR REPLACE FUNCTION get_avg_gpa_by_university(p_university_id INT) |
| | 9 | RETURNS FLOAT AS $func$ |
| | 10 | DECLARE |
| | 11 | avg_gpa FLOAT; |
| | 12 | BEGIN |
| | 13 | SELECT AVG(u.gpa) INTO avg_gpa |
| | 14 | FROM "User" u |
| | 15 | JOIN Studies s ON s.user_id = u.user_id |
| | 16 | JOIN StudyProgram sp ON sp.study_program_id = s.study_program_id |
| | 17 | JOIN Faculty f ON f.faculty_id = sp.faculty_id |
| | 18 | WHERE f.university_id = p_university_id; |
| | 19 | RETURN avg_gpa; |
| | 20 | END; |
| | 21 | $func$ LANGUAGE plpgsql; |
| | 22 | }}} |
| | 23 | |
| | 24 | === get_employment_count_by_company === |
| | 25 | Враќа вкупниот број на вработувања (минати и тековни) за одредена компанија. Се користи за аналитика на компании и рангирање според бројот на вработени alumni. |
| | 26 | {{{ |
| | 27 | CREATE OR REPLACE FUNCTION get_employment_count_by_company(p_company_id INT) |
| | 28 | RETURNS INT AS $func$ |
| | 29 | DECLARE |
| | 30 | emp_count INT; |
| | 31 | BEGIN |
| | 32 | SELECT COUNT(*) INTO emp_count FROM Employment WHERE company_id = p_company_id; |
| | 33 | RETURN emp_count; |
| | 34 | END; |
| | 35 | $func$ LANGUAGE plpgsql; |
| | 36 | }}} |
| | 37 | |
| | 38 | === get_user_skills === |
| | 39 | Враќа табела со сите вештини (ime и тип) кои ги поседува одреден корисник. Се користи при приказ на профилот на корисникот и при пребарување на кандидати по вештини. |
| | 40 | {{{ |
| | 41 | CREATE OR REPLACE FUNCTION get_user_skills(p_user_id INT) |
| | 42 | RETURNS TABLE(skill_name VARCHAR, skill_type VARCHAR) AS $func$ |
| | 43 | BEGIN |
| | 44 | RETURN QUERY |
| | 45 | SELECT s.skill_name, s.type |
| | 46 | FROM Skill s |
| | 47 | JOIN User_Skill us ON us.skill_id = s.skill_id |
| | 48 | WHERE us.user_id = p_user_id; |
| | 49 | END; |
| | 50 | $func$ LANGUAGE plpgsql; |
| | 51 | }}} |
| | 52 | |
| | 53 | ---- |
| | 54 | |
| | 55 | == Процедури == |
| | 56 | |
| | 57 | === add_user_with_studies === |
| | 58 | Додава нов корисник во системот и автоматски го запишува на студиска програма со статус 'active', сè во рамки на една трансакција. Ја имплементира бизнис логиката за регистрација на нов student во системот — корисникот не може да постои без студиска програма. |
| | 59 | {{{ |
| | 60 | CREATE OR REPLACE PROCEDURE add_user_with_studies( |
| | 61 | p_first_name VARCHAR, p_last_name VARCHAR, p_email VARCHAR, |
| | 62 | p_study_program_id INT, p_start_date DATE |
| | 63 | ) |
| | 64 | LANGUAGE plpgsql AS $func$ |
| | 65 | DECLARE v_user_id INT; |
| | 66 | BEGIN |
| | 67 | IF EXISTS (SELECT 1 FROM "User" WHERE email = p_email) THEN |
| | 68 | RAISE EXCEPTION 'Корисник со е-пошта % веќе постои!', p_email; |
| | 69 | END IF; |
| | 70 | INSERT INTO "User"(first_name, last_name, email) |
| | 71 | VALUES(p_first_name, p_last_name, p_email) RETURNING user_id INTO v_user_id; |
| | 72 | INSERT INTO Studies(study_program_id, user_id, start_date, status) |
| | 73 | VALUES(p_study_program_id, v_user_id, p_start_date, 'active'); |
| | 74 | RAISE NOTICE 'Корисник % % успешно додаден! ID: %', p_first_name, p_last_name, v_user_id; |
| | 75 | END; |
| | 76 | $func$; |
| | 77 | }}} |
| | 78 | |
| | 79 | === add_employment_with_salary === |
| | 80 | Креира ново вработување и почетна плата во историјата. Ако корисникот веќе има тековно вработување (is_current = 1), само додава нов запис за плата без да креира дупликат вработување. Ја имплементира логиката за управување со кариерата на alumni. |
| | 81 | {{{ |
| | 82 | CREATE OR REPLACE PROCEDURE add_employment_with_salary( |
| | 83 | p_user_id INT, p_company_id INT, p_start_date DATE, |
| | 84 | p_employment_type VARCHAR, p_salary INT, p_currency VARCHAR |
| | 85 | ) |
| | 86 | LANGUAGE plpgsql AS $func$ |
| | 87 | DECLARE v_employment_id INT; v_existing_emp_id INT; |
| | 88 | BEGIN |
| | 89 | SELECT employment_id INTO v_existing_emp_id |
| | 90 | FROM Employment WHERE user_id = p_user_id AND is_current = 1 LIMIT 1; |
| | 91 | IF v_existing_emp_id IS NOT NULL THEN |
| | 92 | INSERT INTO SalaryHistory(effective_from, currency, salary_amount, employment_id) |
| | 93 | VALUES(p_start_date, p_currency, p_salary, v_existing_emp_id); |
| | 94 | RAISE NOTICE 'Платата ажурирана на % %!', p_salary, p_currency; |
| | 95 | ELSE |
| | 96 | INSERT INTO Employment(start_date, employment_type, currency, |
| | 97 | is_current, promotion_flag, user_id, company_id) |
| | 98 | VALUES(p_start_date, p_employment_type, p_currency, 1, 0, p_user_id, p_company_id) |
| | 99 | RETURNING employment_id INTO v_employment_id; |
| | 100 | INSERT INTO SalaryHistory(effective_from, currency, salary_amount, employment_id) |
| | 101 | VALUES(p_start_date, p_currency, p_salary, v_employment_id); |
| | 102 | RAISE NOTICE 'Ново вработување додадено со плата % %!', p_salary, p_currency; |
| | 103 | END IF; |
| | 104 | END; |
| | 105 | $func$; |
| | 106 | }}} |
| | 107 | |
| | 108 | === add_startup_with_founder === |
| | 109 | Регистрира нов стартап и автоматски го поврзува со основачот. Проверува дали стартапот веќе постои и дали статусот е валиден. Ја имплементира логиката за евидентирање на претприемачката активност на alumni. |
| | 110 | {{{ |
| | 111 | CREATE OR REPLACE PROCEDURE add_startup_with_founder( |
| | 112 | p_name VARCHAR, p_status VARCHAR, p_description VARCHAR, |
| | 113 | p_company_id INT, p_user_id INT |
| | 114 | ) |
| | 115 | LANGUAGE plpgsql AS $func$ |
| | 116 | DECLARE v_startup_id INT; |
| | 117 | BEGIN |
| | 118 | IF EXISTS (SELECT 1 FROM Startup WHERE name = p_name) THEN |
| | 119 | RAISE EXCEPTION 'Стартап со именото % веќе постои!', p_name; |
| | 120 | END IF; |
| | 121 | IF p_status NOT IN ('active', 'closed', 'acquired') THEN |
| | 122 | RAISE EXCEPTION 'Невалиден статус! Дозволени: active, closed, acquired.'; |
| | 123 | END IF; |
| | 124 | INSERT INTO Startup(name, status, description, company_id) |
| | 125 | VALUES(p_name, p_status, p_description, p_company_id) RETURNING startup_id INTO v_startup_id; |
| | 126 | INSERT INTO Founder(user_id, startup_id) VALUES(p_user_id, v_startup_id); |
| | 127 | RAISE NOTICE 'Стартапот % успешно креиран! ID: %', p_name, v_startup_id; |
| | 128 | END; |
| | 129 | $func$; |
| | 130 | }}} |
| | 131 | |
| | 132 | === add_promotion === |
| | 133 | Додава унапредување за постоечко вработување со валидација дека нивоата се различни и зголемувањето е позитивно. Ја имплементира бизнис логиката за следење на кариерниот напредок на alumni. |
| | 134 | {{{ |
| | 135 | CREATE OR REPLACE PROCEDURE add_promotion( |
| | 136 | p_employment_id INT, p_promotion_date DATE, |
| | 137 | p_old_job_level VARCHAR, p_new_job_level VARCHAR, p_salary_increase INT |
| | 138 | ) |
| | 139 | LANGUAGE plpgsql AS $func$ |
| | 140 | BEGIN |
| | 141 | IF p_old_job_level = p_new_job_level THEN |
| | 142 | RAISE EXCEPTION 'Старото и новото ниво не смеат да бидат исти!'; |
| | 143 | END IF; |
| | 144 | INSERT INTO Promotion(promotion_date, old_job_level, new_job_level, |
| | 145 | salary_increase, employment_id) |
| | 146 | VALUES(p_promotion_date, p_old_job_level, p_new_job_level, |
| | 147 | p_salary_increase, p_employment_id); |
| | 148 | RAISE NOTICE 'Унапредување: % -> % за вработување ID %', |
| | 149 | p_old_job_level, p_new_job_level, p_employment_id; |
| | 150 | END; |
| | 151 | $func$; |
| | 152 | }}} |
| | 153 | |
| | 154 | === add_event_with_participants === |
| | 155 | Додава нов настан и автоматски запишува листа на учесници. Ако некој корисник не постои, се прескокнува со предупредување. Ја имплементира логиката за управување со настани и мрежата на alumni. |
| | 156 | {{{ |
| | 157 | CREATE OR REPLACE PROCEDURE add_event_with_participants( |
| | 158 | p_name VARCHAR, p_date DATE, p_location VARCHAR, |
| | 159 | p_company_id INT, p_user_ids INT[] |
| | 160 | ) |
| | 161 | LANGUAGE plpgsql AS $func$ |
| | 162 | DECLARE v_event_id INT; v_user_id INT; |
| | 163 | BEGIN |
| | 164 | INSERT INTO Event(name, "date", location, company_id) |
| | 165 | VALUES(p_name, p_date, p_location, p_company_id) RETURNING event_id INTO v_event_id; |
| | 166 | FOREACH v_user_id IN ARRAY p_user_ids LOOP |
| | 167 | IF NOT EXISTS (SELECT 1 FROM "User" WHERE user_id = v_user_id) THEN |
| | 168 | RAISE WARNING 'Корисник % не постои, прескокнат.', v_user_id; |
| | 169 | CONTINUE; |
| | 170 | END IF; |
| | 171 | INSERT INTO Event_User(event_id, user_id, role) |
| | 172 | VALUES(v_event_id, v_user_id, 'attendee') ON CONFLICT DO NOTHING; |
| | 173 | END LOOP; |
| | 174 | RAISE NOTICE 'Настанот % успешно креиран! ID: %', p_name, v_event_id; |
| | 175 | END; |
| | 176 | $func$; |
| | 177 | }}} |
| | 178 | |
| | 179 | === add_position === |
| | 180 | Додава нова позиција за постоечко вработување и автоматски го превзема company_id. Ја имплементира логиката за следење на работните позиции на alumni низ нивната кариера. |
| | 181 | {{{ |
| | 182 | CREATE OR REPLACE PROCEDURE add_position( |
| | 183 | p_employment_id INT, p_title VARCHAR, |
| | 184 | p_job_level VARCHAR, p_job_category VARCHAR |
| | 185 | ) |
| | 186 | LANGUAGE plpgsql AS $func$ |
| | 187 | DECLARE v_company_id INT; |
| | 188 | BEGIN |
| | 189 | SELECT company_id INTO v_company_id FROM Employment WHERE employment_id = p_employment_id; |
| | 190 | IF NOT FOUND THEN |
| | 191 | RAISE EXCEPTION 'Вработување со ID % не постои!', p_employment_id; |
| | 192 | END IF; |
| | 193 | INSERT INTO position(title, job_level, job_category, employment_id, company_id) |
| | 194 | VALUES(p_title, p_job_level, p_job_category, p_employment_id, v_company_id); |
| | 195 | RAISE NOTICE 'Позиција % успешно додадена за вработување ID %', p_title, p_employment_id; |
| | 196 | END; |
| | 197 | $func$; |
| | 198 | }}} |
| | 199 | |
| | 200 | === add_internship === |
| | 201 | Додава пракса за корисник во компанија со валидација на датуми. Ја имплементира бизнис логиката за евидентирање на студентски пракси пред или за време на студирањето. |
| | 202 | {{{ |
| | 203 | CREATE OR REPLACE PROCEDURE add_internship( |
| | 204 | p_user_id INT, p_company_id INT, p_start_date DATE, p_end_date DATE |
| | 205 | ) |
| | 206 | LANGUAGE plpgsql AS $func$ |
| | 207 | BEGIN |
| | 208 | IF p_end_date IS NOT NULL AND p_end_date <= p_start_date THEN |
| | 209 | RAISE EXCEPTION 'Датумот на завршување мора да биде после почетокот!'; |
| | 210 | END IF; |
| | 211 | INSERT INTO Internship(start_date, end_date, user_id, company_id) |
| | 212 | VALUES(p_start_date, p_end_date, p_user_id, p_company_id); |
| | 213 | RAISE NOTICE 'Пракса успешно додадена за корисник % во компанија %', p_user_id, p_company_id; |
| | 214 | END; |
| | 215 | $func$; |
| | 216 | }}} |
| | 217 | |
| | 218 | === add_award === |
| | 219 | Додава награда за корисник поврзана со компанија. Ја имплементира логиката за следење на достигнувањата и признанијата на alumni во нивната кариера. |
| | 220 | {{{ |
| | 221 | CREATE OR REPLACE PROCEDURE add_award( |
| | 222 | p_user_id INT, p_company_id INT, |
| | 223 | p_title VARCHAR, p_organization VARCHAR, p_date DATE |
| | 224 | ) |
| | 225 | LANGUAGE plpgsql AS $func$ |
| | 226 | BEGIN |
| | 227 | INSERT INTO Award(title, organization, "date", company_id, user_id) |
| | 228 | VALUES(p_title, p_organization, p_date, p_company_id, p_user_id); |
| | 229 | RAISE NOTICE 'Награда "%" успешно додадена за корисник %', p_title, p_user_id; |
| | 230 | END; |
| | 231 | $func$; |
| | 232 | }}} |
| | 233 | |
| | 234 | === add_course_completion === |
| | 235 | Запишува корисник на дополнителен курс или ажурира статус ако веќе е запишан. Ја имплементира логиката за следење на континуираното образование и професионален развој на alumni. |
| | 236 | {{{ |
| | 237 | CREATE OR REPLACE PROCEDURE add_course_completion( |
| | 238 | p_user_id INT, p_course_id INT, |
| | 239 | p_status VARCHAR, p_completion_date DATE DEFAULT NULL |
| | 240 | ) |
| | 241 | LANGUAGE plpgsql AS $func$ |
| | 242 | BEGIN |
| | 243 | IF p_status NOT IN ('in-progress', 'completed', 'failed') THEN |
| | 244 | RAISE EXCEPTION 'Невалиден статус!'; |
| | 245 | END IF; |
| | 246 | IF EXISTS (SELECT 1 FROM AdditionalCourse_User |
| | 247 | WHERE user_id = p_user_id AND additional_course_id = p_course_id) THEN |
| | 248 | UPDATE AdditionalCourse_User SET status = p_status, completion_date = p_completion_date |
| | 249 | WHERE user_id = p_user_id AND additional_course_id = p_course_id; |
| | 250 | ELSE |
| | 251 | INSERT INTO AdditionalCourse_User(user_id, additional_course_id, completion_date, status) |
| | 252 | VALUES(p_user_id, p_course_id, p_completion_date, p_status); |
| | 253 | END IF; |
| | 254 | RAISE NOTICE 'Статус % за курс % на корисник % ажуриран.', p_status, p_course_id, p_user_id; |
| | 255 | END; |
| | 256 | $func$; |
| | 257 | }}} |
| | 258 | |
| | 259 | === update_study_status === |
| | 260 | Ажурира статусот на студии (active → completed/dropped). Ако статусот е 'completed', автоматски генерира диплома. Ја имплементира бизнис логиката за завршување на студиите. |
| | 261 | {{{ |
| | 262 | CREATE OR REPLACE PROCEDURE update_study_status( |
| | 263 | p_studies_id INT, p_new_status VARCHAR, p_end_date DATE DEFAULT NULL |
| | 264 | ) |
| | 265 | LANGUAGE plpgsql AS $func$ |
| | 266 | DECLARE v_start_date DATE; |
| | 267 | BEGIN |
| | 268 | SELECT start_date INTO v_start_date FROM Studies WHERE studies_id = p_studies_id; |
| | 269 | IF NOT FOUND THEN RAISE EXCEPTION 'Студии со ID % не постојат!', p_studies_id; END IF; |
| | 270 | UPDATE Studies SET status = p_new_status, end_date = p_end_date WHERE studies_id = p_studies_id; |
| | 271 | IF p_new_status = 'completed' AND p_end_date IS NOT NULL THEN |
| | 272 | INSERT INTO Diploma(graduation_date, thesis_title, studies_id) |
| | 273 | VALUES(p_end_date, 'Дипломски труд ' || p_studies_id, p_studies_id) |
| | 274 | ON CONFLICT DO NOTHING; |
| | 275 | RAISE NOTICE 'Студиите завршени и диплома додадена!'; |
| | 276 | END IF; |
| | 277 | END; |
| | 278 | $func$; |
| | 279 | }}} |
| | 280 | |
| | 281 | === add_skill_to_user === |
| | 282 | Додава вештина на корисник со проверка за дупликат. Ја имплементира логиката за управување со портфолиото на вештини на alumni. |
| | 283 | {{{ |
| | 284 | CREATE OR REPLACE PROCEDURE add_skill_to_user(p_user_id INT, p_skill_id INT) |
| | 285 | LANGUAGE plpgsql AS $func$ |
| | 286 | BEGIN |
| | 287 | IF EXISTS (SELECT 1 FROM User_Skill WHERE user_id = p_user_id AND skill_id = p_skill_id) THEN |
| | 288 | RAISE EXCEPTION 'Корисникот веќе ја поседува оваа вештина!'; |
| | 289 | END IF; |
| | 290 | INSERT INTO User_Skill(user_id, skill_id) VALUES(p_user_id, p_skill_id); |
| | 291 | RAISE NOTICE 'Вештина % успешно додадена на корисник %', p_skill_id, p_user_id; |
| | 292 | END; |
| | 293 | $func$; |
| | 294 | }}} |
| | 295 | |
| | 296 | === remove_skill_from_user === |
| | 297 | Брише вештина од корисник. Се користи кога корисникот сака да го ажурира своето профилно портфолио на вештини. |
| | 298 | {{{ |
| | 299 | CREATE OR REPLACE PROCEDURE remove_skill_from_user(p_user_id INT, p_skill_id INT) |
| | 300 | LANGUAGE plpgsql AS $func$ |
| | 301 | BEGIN |
| | 302 | IF NOT EXISTS (SELECT 1 FROM User_Skill WHERE user_id = p_user_id AND skill_id = p_skill_id) THEN |
| | 303 | RAISE EXCEPTION 'Корисник % нема вештина со ID %!', p_user_id, p_skill_id; |
| | 304 | END IF; |
| | 305 | DELETE FROM User_Skill WHERE user_id = p_user_id AND skill_id = p_skill_id; |
| | 306 | RAISE NOTICE 'Вештина % отстранета од корисник %', p_skill_id, p_user_id; |
| | 307 | END; |
| | 308 | $func$; |
| | 309 | }}} |
| | 310 | |
| | 311 | === end_employment === |
| | 312 | Завршува тековно вработување — поставува is_current = 0 и end_date, и го затвора последниот запис во SalaryHistory. Ја имплементира логиката за евидентирање на напуштање на работното место. |
| | 313 | {{{ |
| | 314 | CREATE OR REPLACE PROCEDURE end_employment(p_employment_id INT, p_end_date DATE) |
| | 315 | LANGUAGE plpgsql AS $func$ |
| | 316 | BEGIN |
| | 317 | IF NOT EXISTS (SELECT 1 FROM Employment WHERE employment_id = p_employment_id AND is_current = 1) THEN |
| | 318 | RAISE EXCEPTION 'Вработувањето не постои или веќе е завршено!'; |
| | 319 | END IF; |
| | 320 | UPDATE Employment SET is_current = 0, end_date = p_end_date WHERE employment_id = p_employment_id; |
| | 321 | UPDATE SalaryHistory SET effective_to = p_end_date |
| | 322 | WHERE employment_id = p_employment_id AND effective_to IS NULL; |
| | 323 | RAISE NOTICE 'Вработување % завршено на %', p_employment_id, p_end_date; |
| | 324 | END; |
| | 325 | $func$; |
| | 326 | }}} |
| | 327 | |
| | 328 | === update_salary === |
| | 329 | Додава нов запис во SalaryHistory и го затвора претходниот. Ја имплементира бизнис логиката за следење на историјата на плати на alumni низ времето. |
| | 330 | {{{ |
| | 331 | CREATE OR REPLACE PROCEDURE update_salary( |
| | 332 | p_employment_id INT, p_new_salary INT, |
| | 333 | p_currency VARCHAR, p_effective_from DATE |
| | 334 | ) |
| | 335 | LANGUAGE plpgsql AS $func$ |
| | 336 | BEGIN |
| | 337 | IF p_new_salary <= 0 THEN RAISE EXCEPTION 'Платата мора да биде позитивна!'; END IF; |
| | 338 | UPDATE SalaryHistory SET effective_to = p_effective_from - 1 |
| | 339 | WHERE employment_id = p_employment_id AND effective_to IS NULL; |
| | 340 | INSERT INTO SalaryHistory(effective_from, currency, salary_amount, employment_id) |
| | 341 | VALUES(p_effective_from, p_currency, p_new_salary, p_employment_id); |
| | 342 | RAISE NOTICE 'Платата ажурирана на % % за вработување %', p_new_salary, p_currency, p_employment_id; |
| | 343 | END; |
| | 344 | $func$; |
| | 345 | }}} |
| | 346 | |
| | 347 | === enroll_existing_user === |
| | 348 | Запишува постоечки корисник на нова студиска програма. Проверува дали веќе е активно запишан. Се користи кога alumni продолжува со образование (втор циклус, PhD). |
| | 349 | {{{ |
| | 350 | CREATE OR REPLACE PROCEDURE enroll_existing_user( |
| | 351 | p_user_id INT, p_study_program_id INT, p_start_date DATE |
| | 352 | ) |
| | 353 | LANGUAGE plpgsql AS $func$ |
| | 354 | BEGIN |
| | 355 | IF EXISTS (SELECT 1 FROM Studies WHERE user_id = p_user_id |
| | 356 | AND study_program_id = p_study_program_id AND status = 'active') THEN |
| | 357 | RAISE EXCEPTION 'Корисникот веќе е активно запишан на оваа програма!'; |
| | 358 | END IF; |
| | 359 | INSERT INTO Studies(study_program_id, user_id, start_date, status) |
| | 360 | VALUES(p_study_program_id, p_user_id, p_start_date, 'active'); |
| | 361 | RAISE NOTICE 'Корисник % успешно запишан на програма %', p_user_id, p_study_program_id; |
| | 362 | END; |
| | 363 | $func$; |
| | 364 | }}} |
| | 365 | |
| | 366 | === add_diploma === |
| | 367 | Директно додава диплома за завршени студии. Дозволено само ако студиите имаат статус 'completed'. Ја имплементира логиката за потврда на академската квалификација на alumni. |
| | 368 | {{{ |
| | 369 | CREATE OR REPLACE PROCEDURE add_diploma( |
| | 370 | p_studies_id INT, p_graduation_date DATE, p_thesis_title VARCHAR |
| | 371 | ) |
| | 372 | LANGUAGE plpgsql AS $func$ |
| | 373 | DECLARE v_status VARCHAR; |
| | 374 | BEGIN |
| | 375 | SELECT status INTO v_status FROM Studies WHERE studies_id = p_studies_id; |
| | 376 | IF v_status != 'completed' THEN |
| | 377 | RAISE EXCEPTION 'Не може диплома за студии со статус "%"!', v_status; |
| | 378 | END IF; |
| | 379 | IF EXISTS (SELECT 1 FROM Diploma WHERE studies_id = p_studies_id) THEN |
| | 380 | RAISE EXCEPTION 'Диплома за овие студии веќе постои!'; |
| | 381 | END IF; |
| | 382 | INSERT INTO Diploma(graduation_date, thesis_title, studies_id) |
| | 383 | VALUES(p_graduation_date, p_thesis_title, p_studies_id); |
| | 384 | RAISE NOTICE 'Диплома успешно додадена за studies_id %', p_studies_id; |
| | 385 | END; |
| | 386 | $func$; |
| | 387 | }}} |
| | 388 | |
| | 389 | === add_company === |
| | 390 | Додава нова компанија со валидација на индустрија и број на вработени. Се користи при проширување на базата на компании со кои alumni се поврзани. |
| | 391 | {{{ |
| | 392 | CREATE OR REPLACE PROCEDURE add_company( |
| | 393 | p_name VARCHAR, p_number_employees INT, p_industry_id INT |
| | 394 | ) |
| | 395 | LANGUAGE plpgsql AS $func$ |
| | 396 | BEGIN |
| | 397 | IF EXISTS (SELECT 1 FROM Company WHERE name = p_name) THEN |
| | 398 | RAISE EXCEPTION 'Компанија со именото % веќе постои!', p_name; |
| | 399 | END IF; |
| | 400 | IF p_number_employees < 0 THEN |
| | 401 | RAISE EXCEPTION 'Бројот на вработени не може да биде негативен!'; |
| | 402 | END IF; |
| | 403 | INSERT INTO Company(name, number_employees, industry_id) |
| | 404 | VALUES(p_name, p_number_employees, p_industry_id); |
| | 405 | RAISE NOTICE 'Компанија % успешно додадена!', p_name; |
| | 406 | END; |
| | 407 | $func$; |
| | 408 | }}} |
| | 409 | |
| | 410 | === add_industry === |
| | 411 | Додава нова индустрија со проверка за уникатност. Се користи при проширување на категоризацијата на компании во системот. |
| | 412 | {{{ |
| | 413 | CREATE OR REPLACE PROCEDURE add_industry(p_industry_name VARCHAR, p_sector_category VARCHAR) |
| | 414 | LANGUAGE plpgsql AS $func$ |
| | 415 | BEGIN |
| | 416 | IF EXISTS (SELECT 1 FROM Industry WHERE industry_name = p_industry_name) THEN |
| | 417 | RAISE EXCEPTION 'Индустрија со именото % веќе постои!', p_industry_name; |
| | 418 | END IF; |
| | 419 | INSERT INTO Industry(industry_name, sector_category) VALUES(p_industry_name, p_sector_category); |
| | 420 | RAISE NOTICE 'Индустрија % успешно додадена!', p_industry_name; |
| | 421 | END; |
| | 422 | $func$; |
| | 423 | }}} |
| | 424 | |
| | 425 | === update_startup_status === |
| | 426 | Менува статусот на стартап (active → closed/acquired). Ја имплементира логиката за следење на животниот циклус на стартапите основани од alumni. |
| | 427 | {{{ |
| | 428 | CREATE OR REPLACE PROCEDURE update_startup_status(p_startup_id INT, p_new_status VARCHAR) |
| | 429 | LANGUAGE plpgsql AS $func$ |
| | 430 | DECLARE v_current_status VARCHAR; |
| | 431 | BEGIN |
| | 432 | SELECT status INTO v_current_status FROM Startup WHERE startup_id = p_startup_id; |
| | 433 | IF NOT FOUND THEN RAISE EXCEPTION 'Стартап со ID % не постои!', p_startup_id; END IF; |
| | 434 | IF v_current_status = p_new_status THEN |
| | 435 | RAISE EXCEPTION 'Стартапот веќе има статус "%"!', p_new_status; |
| | 436 | END IF; |
| | 437 | UPDATE Startup SET status = p_new_status WHERE startup_id = p_startup_id; |
| | 438 | RAISE NOTICE 'Стартап %: статус сменет од % на %', p_startup_id, v_current_status, p_new_status; |
| | 439 | END; |
| | 440 | $func$; |
| | 441 | }}} |
| | 442 | |
| | 443 | === add_founder_to_startup === |
| | 444 | Додава уште еден основач на постоечки стартап со проверка за дупликат. Се користи кога стартап има повеќе соосновачи меѓу alumni. |
| | 445 | {{{ |
| | 446 | CREATE OR REPLACE PROCEDURE add_founder_to_startup(p_user_id INT, p_startup_id INT) |
| | 447 | LANGUAGE plpgsql AS $func$ |
| | 448 | BEGIN |
| | 449 | IF EXISTS (SELECT 1 FROM Founder WHERE user_id = p_user_id AND startup_id = p_startup_id) THEN |
| | 450 | RAISE EXCEPTION 'Корисникот веќе е основач на овој стартап!'; |
| | 451 | END IF; |
| | 452 | INSERT INTO Founder(user_id, startup_id) VALUES(p_user_id, p_startup_id); |
| | 453 | RAISE NOTICE 'Корисник % додаден како основач на стартап %', p_user_id, p_startup_id; |
| | 454 | END; |
| | 455 | $func$; |
| | 456 | }}} |
| | 457 | |
| | 458 | === remove_user === |
| | 459 | Безбедно брише корисник од системот. Тригерот trg_prevent_delete_active_student автоматски го спречува бришењето ако корисникот има активни студии, обезбедувајќи интегритет на податоците. |
| | 460 | {{{ |
| | 461 | CREATE OR REPLACE PROCEDURE remove_user(p_user_id INT) |
| | 462 | LANGUAGE plpgsql AS $func$ |
| | 463 | BEGIN |
| | 464 | IF NOT EXISTS (SELECT 1 FROM "User" WHERE user_id = p_user_id) THEN |
| | 465 | RAISE EXCEPTION 'Корисник со ID % не постои!', p_user_id; |
| | 466 | END IF; |
| | 467 | DELETE FROM "User" WHERE user_id = p_user_id; |
| | 468 | RAISE NOTICE 'Корисник % успешно избришан!', p_user_id; |
| | 469 | END; |
| | 470 | $func$; |
| | 471 | }}} |
| | 472 | |
| | 473 | === cancel_internship === |
| | 474 | Предвремено завршува пракса со поставување на end_date. Се користи при предвремено прекинување на пракса поради различни околности. |
| | 475 | {{{ |
| | 476 | CREATE OR REPLACE PROCEDURE cancel_internship(p_internship_id INT, p_end_date DATE) |
| | 477 | LANGUAGE plpgsql AS $func$ |
| | 478 | DECLARE v_start_date DATE; |
| | 479 | BEGIN |
| | 480 | SELECT start_date INTO v_start_date FROM Internship WHERE internship_id = p_internship_id; |
| | 481 | IF NOT FOUND THEN RAISE EXCEPTION 'Пракса со ID % не постои!', p_internship_id; END IF; |
| | 482 | IF p_end_date <= v_start_date THEN |
| | 483 | RAISE EXCEPTION 'Датумот на завршување мора да биде после почетокот!'; |
| | 484 | END IF; |
| | 485 | UPDATE Internship SET end_date = p_end_date WHERE internship_id = p_internship_id; |
| | 486 | RAISE NOTICE 'Пракса % завршена на датум %', p_internship_id, p_end_date; |
| | 487 | END; |
| | 488 | $func$; |
| | 489 | }}} |
| | 490 | |
| | 491 | ---- |
| | 492 | |
| | 493 | == Тригери == |
| | 494 | |
| | 495 | === trg_prevent_delete_active_student === |
| | 496 | Спречува бришење на корисник кој моментално има активни студии, фрлајќи исклучок пред да се изврши DELETE операцијата. Ја имплементира бизнис логиката за заштита на академските записи — активен студент не може да биде избришан од системот. |
| | 497 | {{{ |
| | 498 | CREATE OR REPLACE FUNCTION prevent_delete_active_student() |
| | 499 | RETURNS TRIGGER AS $func$ |
| | 500 | BEGIN |
| | 501 | IF EXISTS (SELECT 1 FROM Studies WHERE user_id = OLD.user_id AND status = 'active') THEN |
| | 502 | RAISE EXCEPTION 'Не може да се избрише корисник со активни студии!'; |
| | 503 | END IF; |
| | 504 | RETURN OLD; |
| | 505 | END; |
| | 506 | $func$ LANGUAGE plpgsql; |
| | 507 | |
| | 508 | CREATE OR REPLACE TRIGGER trg_prevent_delete_active_student |
| | 509 | BEFORE DELETE ON "User" |
| | 510 | FOR EACH ROW EXECUTE FUNCTION prevent_delete_active_student(); |
| | 511 | }}} |
| | 512 | |
| | 513 | === trg_update_current_employment === |
| | 514 | При додавање на ново тековно вработување (is_current = 1), автоматски ги поставува сите претходни вработувања на истиот корисник на is_current = 0. Ја имплементира бизнис логиката дека корисникот може да има само едно тековно вработување истовремено. |
| | 515 | {{{ |
| | 516 | CREATE OR REPLACE FUNCTION update_current_employment() |
| | 517 | RETURNS TRIGGER AS $func$ |
| | 518 | BEGIN |
| | 519 | IF NEW.is_current = 1 THEN |
| | 520 | UPDATE Employment SET is_current = 0 |
| | 521 | WHERE user_id = NEW.user_id |
| | 522 | AND employment_id != NEW.employment_id |
| | 523 | AND is_current = 1; |
| | 524 | END IF; |
| | 525 | RETURN NEW; |
| | 526 | END; |
| | 527 | $func$ LANGUAGE plpgsql; |
| | 528 | |
| | 529 | CREATE OR REPLACE TRIGGER trg_update_current_employment |
| | 530 | AFTER INSERT ON Employment |
| | 531 | FOR EACH ROW EXECUTE FUNCTION update_current_employment(); |
| | 532 | }}} |
| | 533 | |
| | 534 | === trg_check_promotion_flag === |
| | 535 | При додавање на нова промоција, автоматски го поставува promotion_flag на 1 во табелата Employment доколку не е веќе поставен. Ја имплементира логиката за автоматско означување на вработувања со историја на унапредување, без потреба од рачно ажурирање. |
| | 536 | {{{ |
| | 537 | CREATE OR REPLACE FUNCTION check_promotion_flag() |
| | 538 | RETURNS TRIGGER AS $func$ |
| | 539 | DECLARE v_flag INT; |
| | 540 | BEGIN |
| | 541 | SELECT promotion_flag INTO v_flag FROM Employment WHERE employment_id = NEW.employment_id; |
| | 542 | IF v_flag = 0 THEN |
| | 543 | UPDATE Employment SET promotion_flag = 1 WHERE employment_id = NEW.employment_id; |
| | 544 | RAISE NOTICE 'promotion_flag автоматски поставен на 1!'; |
| | 545 | END IF; |
| | 546 | RETURN NEW; |
| | 547 | END; |
| | 548 | $func$ LANGUAGE plpgsql; |
| | 549 | |
| | 550 | CREATE OR REPLACE TRIGGER trg_check_promotion_flag |
| | 551 | AFTER INSERT ON Promotion |
| | 552 | FOR EACH ROW EXECUTE FUNCTION check_promotion_flag(); |
| | 553 | }}} |