| | 1 | = Сезонска анализа: споредба на исти месец во различни години = |
| | 2 | |
| | 3 | == Опис == |
| | 4 | |
| | 5 | Извештајот го споредува приходот во секој месец од тековната година со истиот месец од претходната година, со процент на промена. Користи CTE со две нивоа и прозорска функција RANK за рангирање на месеците. |
| | 6 | |
| | 7 | == SQL решение == |
| | 8 | |
| | 9 | {{{ |
| | 10 | CREATE OR REPLACE FUNCTION project.get_yoy_monthly_comparison() |
| | 11 | RETURNS TABLE ( |
| | 12 | month_num INT, |
| | 13 | month_name TEXT, |
| | 14 | current_year_revenue NUMERIC, |
| | 15 | previous_year_revenue NUMERIC, |
| | 16 | change_pct NUMERIC, |
| | 17 | rank_in_year INT |
| | 18 | ) |
| | 19 | LANGUAGE sql |
| | 20 | AS $$ |
| | 21 | WITH monthly_rev AS ( |
| | 22 | SELECT |
| | 23 | EXTRACT(YEAR FROM p.payment_date)::INT AS yr, |
| | 24 | EXTRACT(MONTH FROM p.payment_date)::INT AS mo, |
| | 25 | SUM(p.amount)::numeric AS revenue |
| | 26 | FROM project.payment p |
| | 27 | JOIN project.orders o ON o.order_id = p.order_id |
| | 28 | WHERE o.status = 'ПЛАТЕНА' |
| | 29 | GROUP BY 1, 2 |
| | 30 | ), |
| | 31 | yoy AS ( |
| | 32 | SELECT |
| | 33 | curr.yr, curr.mo, curr.revenue AS curr_rev, |
| | 34 | prev.revenue AS prev_rev, |
| | 35 | ROUND((100.0 * (curr.revenue - prev.revenue) |
| | 36 | / NULLIF(prev.revenue, 0))::numeric, 2) AS change_pct |
| | 37 | FROM monthly_rev curr |
| | 38 | LEFT JOIN monthly_rev prev |
| | 39 | ON prev.yr = curr.yr - 1 AND prev.mo = curr.mo |
| | 40 | WHERE curr.yr = EXTRACT(YEAR FROM NOW())::INT |
| | 41 | ), |
| | 42 | ranked AS ( |
| | 43 | SELECT yr, mo, curr_rev, prev_rev, change_pct, |
| | 44 | RANK() OVER (ORDER BY curr_rev DESC) AS rnk |
| | 45 | FROM yoy |
| | 46 | ) |
| | 47 | SELECT |
| | 48 | mo, |
| | 49 | TO_CHAR(TO_DATE(mo::TEXT, 'MM'), 'Month')::TEXT, |
| | 50 | curr_rev, |
| | 51 | COALESCE(prev_rev, 0), |
| | 52 | COALESCE(change_pct, 0), |
| | 53 | rnk::INT |
| | 54 | FROM ranked |
| | 55 | WHERE curr_rev > ( |
| | 56 | SELECT AVG(revenue) FROM monthly_rev |
| | 57 | WHERE yr = EXTRACT(YEAR FROM NOW())::INT |
| | 58 | ) |
| | 59 | ORDER BY 1; |
| | 60 | $$; |
| | 61 | }}} |
| | 62 | |
| | 63 | == Релациона алгебра == |
| | 64 | |
| | 65 | {{{ |
| | 66 | P(payment_id, order_id, amount, payment_date) |
| | 67 | O(order_id, status) |
| | 68 | |
| | 69 | J1 ← P ⨝ P.order_id = O.order_id O |
| | 70 | F1 ← σ status='ПЛАТЕНА' (J1) |
| | 71 | |
| | 72 | G1 ← γ yr, mo; SUM(amount) → revenue (F1) |
| | 73 | |
| | 74 | J2 ← G1 ⨝ G1.yr = G1b.yr + 1 ∧ G1.mo = G1b.mo G1b |
| | 75 | F2 ← σ yr = YEAR(NOW()) (J2) |
| | 76 | |
| | 77 | W ← γ yr, mo; RANK() OVER (ORDER BY curr_rev DESC) → rnk (F2) |
| | 78 | F3 ← σ curr_rev > AVG(revenue) (W) |
| | 79 | |
| | 80 | R ← π month_num, month_name, current_year_revenue, |
| | 81 | previous_year_revenue, change_pct, rank_in_year (F3) |
| | 82 | |
| | 83 | R_final ← τ month_num ASC (R) |
| | 84 | }}} |