Функции, процедури, тригери : functions.sql

File functions.sql, 8.0 KB (added by 231107, 2 weeks ago)
Line 
1--================================================================================================================
2-- FUNCTIONS
3--================================================================================================================
4
5-- 1. Конверзија на валути
6--Функцијата служи за конвертирање на паричен износ од една валута во друга според
7-- курсевите зачувани во табелата Exchange_rate за одреден датум.
8-- Доколку валутите се исти се враќа соодветниот износ,
9-- а доколку не постои курс за дадениот датум се фрла exception.
10CREATE OR REPLACE FUNCTION fn_convert_currency(
11 p_from_curr INT,
12 p_to_curr INT,
13 p_amount DECIMAL(20, 2),
14 p_date DATE DEFAULT CURRENT_DATE
15)
16 RETURNS DECIMAL(20, 2) AS
17$$
18DECLARE
19 v_rate DECIMAL(15, 6);
20BEGIN
21 IF p_from_curr = p_to_curr THEN
22 RETURN p_amount;
23 END IF;
24
25 SELECT (er_to.rate / er_from.rate)
26 INTO v_rate
27 FROM Exchange_rate er_from
28 JOIN Exchange_rate er_to
29 ON er_to.currency_id = p_to_curr
30 AND er_to.date_updated = p_date
31 WHERE er_from.currency_id = p_from_curr
32 AND er_from.date_updated = p_date;
33
34 IF v_rate IS NULL THEN
35 RAISE EXCEPTION 'Nema kurs za %', p_date;
36 END IF;
37
38 RETURN ROUND(p_amount * v_rate, 2);
39END;
40$$ LANGUAGE plpgsql;
41
42SELECT fn_convert_currency(2, 3, 100.00, '2026-04-12');
43
44
45-- 2. Проверка дали сметка е активна
46--Функцијата проверува дали даден клиент и неговата сметка се активни.
47-- Се користи како безбедносна проверка пред извршување финансиски операции како трансфер, уплата или исплата.
48-- Доколку сметката не постои или статусот не е ACTIVE, враќа FALSE.
49CREATE OR REPLACE FUNCTION fn_is_account_eligible(p_account_id INT)
50 RETURNS BOOLEAN AS
51$$
52DECLARE
53 v_acc_status VARCHAR(20);
54 v_client_status VARCHAR(20);
55BEGIN
56 SELECT a.status, c.status
57 INTO v_acc_status, v_client_status
58 FROM Account a
59 JOIN Client c ON a.client_id = c.client_id
60 WHERE a.account_id = p_account_id;
61
62 IF NOT FOUND THEN
63 RETURN FALSE;
64 END IF;
65
66 RETURN (v_acc_status = 'ACTIVE' AND v_client_status = 'ACTIVE');
67END;
68$$ LANGUAGE plpgsql;
69
70SELECT fn_is_account_eligible(1003);
71
72
73-- 3. Враќа вкупен неплатен долг на клиент (сума на сите PENDING/LATE рати)
74--Функцијата го пресметува вкупниот неплатен долг на клиентот преку собирање
75-- на сите рати со статус PENDING или LATE од одобрени кредити. Нејзината намена е следење
76-- на задолженоста на клиентите, кредитна анализа.
77-- Доколку клиентот нема неплатени обврски функцијата враќа вредност 0.
78CREATE OR REPLACE FUNCTION fn_get_client_total_debt(p_client_id INT)
79 RETURNS DECIMAL(20, 2) AS
80$$
81DECLARE
82 v_total DECIMAL(20, 2);
83BEGIN
84 SELECT COALESCE(SUM(li.amount), 0)
85 INTO v_total
86 FROM Loan_installment li
87 JOIN Loan l ON li.loan_id = l.loan_id
88 WHERE l.client_id = p_client_id
89 AND li.status IN ('PENDING', 'LATE')
90 AND l.status = 'APPROVED';
91
92 RETURN v_total;
93END;
94$$ LANGUAGE plpgsql;
95
96
97SELECT fn_get_client_total_debt(318290);
98
99
100
101-- 4. Враќа преостаната сума за отплата на кредит
102--Функцијата враќа детален преглед за состојбата на конкретен кредит.
103-- Се прикажуваат вкупниот износ, веќе исплатениот дел, преостанатиот долг,
104-- како и бројот на доцнења и неплатени рати.
105-- Доколку кредитот не постои, се прикажува соодветна грешка.
106CREATE OR REPLACE FUNCTION fn_get_loan_remaining_amount(p_loan_id INT)
107 RETURNS TABLE
108 (
109 loan_id INT,
110 total_amount DECIMAL(15, 2),
111 paid_amount DECIMAL(15, 2),
112 remaining_amount DECIMAL(15, 2),
113 late_count INT,
114 pending_count INT
115 )
116AS
117$$
118BEGIN
119 RETURN QUERY
120 SELECT l.loan_id,
121 l.amount,
122 COALESCE(SUM(li.amount) FILTER (WHERE li.status = 'PAID'), 0)::DECIMAL(15, 2),
123 COALESCE(SUM(li.amount) FILTER (WHERE li.status != 'PAID'), 0)::DECIMAL(15, 2),
124 COUNT(*) FILTER (WHERE li.status = 'LATE')::INT,
125 COUNT(*) FILTER (WHERE li.status = 'PENDING')::INT
126 FROM Loan l
127 JOIN Loan_installment li ON l.loan_id = li.loan_id
128 WHERE l.loan_id = p_loan_id
129 GROUP BY l.loan_id, l.amount;
130
131 IF NOT FOUND THEN
132 RAISE EXCEPTION 'Кредитот со ID % не постои.', p_loan_id;
133 END IF;
134END;
135$$ LANGUAGE plpgsql;
136
137
138SELECT *
139FROM fn_get_loan_remaining_amount(86961);
140
141
142-- 5. Го пресметува очекуваниот износ на камата за штедна сметка за даден период
143--Оваа функција пресметува очекувана камата за штедна сметка во зададен временски период.
144-- Поддржува едноставна (SIMPLE) и сложена (COMPOUND) камата, како и различни периоди на капитализација.
145-- Пресметката се базира на моменталното салдо и каматната стапка на сметката.
146CREATE OR REPLACE FUNCTION fn_calculate_savings_interest(
147 p_account_id INT,
148 p_period_start DATE,
149 p_period_end DATE
150)
151 RETURNS DECIMAL(20, 2) AS
152$$
153DECLARE
154 v_balance DECIMAL(20, 2);
155 v_interest_rate DECIMAL(5, 2);
156 v_interest_period VARCHAR(20);
157 v_capitalization VARCHAR(20);
158 v_days INT;
159 v_interest_result DECIMAL(20, 2);
160
161 v_time_factor_years DECIMAL(20, 6);
162 v_compounding_per_year INT;
163BEGIN
164 SELECT a.balance, sa.interest_rate, sa.interest_period, sa.capitalization_type
165 INTO v_balance, v_interest_rate, v_interest_period, v_capitalization
166 FROM Account a
167 JOIN SavingsAccount sa ON a.account_id = sa.account_id
168 WHERE a.account_id = p_account_id;
169
170 IF NOT FOUND THEN
171 RAISE EXCEPTION 'Сметка % не е штедна сметка или не постои.', p_account_id;
172 END IF;
173
174 v_days := p_period_end - p_period_start;
175
176 IF v_interest_period = 'DAILY' THEN
177 v_time_factor_years := v_days / 365.0;
178 v_compounding_per_year := 365;
179
180 ELSIF v_interest_period = 'MONTHLY' THEN
181 v_time_factor_years := v_days / 365.0;
182 v_compounding_per_year := 12;
183
184 ELSE
185
186 v_time_factor_years := v_days / 365.0;
187 v_compounding_per_year := 1;
188 END IF;
189
190 -- SIMPLE INTEREST
191 IF v_capitalization = 'SIMPLE' THEN
192
193 v_interest_result :=
194 v_balance * (v_interest_rate / 100.0) * v_time_factor_years;
195
196 -- COMPOUND INTEREST
197 ELSE
198
199 v_interest_result :=
200 v_balance * (
201 POWER(
202 1 + (v_interest_rate / 100.0) / v_compounding_per_year,
203 v_compounding_per_year * v_time_factor_years
204 ) - 1
205 );
206
207 END IF;
208
209 RETURN ROUND(v_interest_result, 2);
210END;
211$$ LANGUAGE plpgsql;
212
213
214SELECT fn_calculate_savings_interest(201, '2026-04-01', '2026-04-30');
215