| | 1 | = Келнери со надпросечна ефикасност и нивниот најпрофитабилен производ = |
| | 2 | |
| | 3 | == Опис == |
| | 4 | |
| | 5 | Извештајот ги прикажува келнерите чие просечно време до плаќање е помало од просекот на сите келнери, заедно со производот што им донел најголем приход. Користи повеќе нивоа на вгнездување: (1) агрегација по келнер, (2) споредба со глобален просек, (3) корелационен потпрашалник за најпрофитабилен производ. |
| | 6 | |
| | 7 | == SQL решение == |
| | 8 | |
| | 9 | {{{ |
| | 10 | CREATE OR REPLACE FUNCTION project.get_efficient_waiters_top_product() |
| | 11 | RETURNS TABLE ( |
| | 12 | user_id INT, |
| | 13 | waiter_name TEXT, |
| | 14 | avg_minutes NUMERIC, |
| | 15 | global_avg_minutes NUMERIC, |
| | 16 | total_orders BIGINT, |
| | 17 | top_product TEXT, |
| | 18 | top_product_revenue NUMERIC |
| | 19 | ) |
| | 20 | LANGUAGE sql |
| | 21 | AS $$ |
| | 22 | WITH waiter_stats AS ( |
| | 23 | SELECT |
| | 24 | u.user_id AS uid, |
| | 25 | (u.first_name || ' ' || u.last_name)::TEXT AS wname, |
| | 26 | AVG(EXTRACT(EPOCH FROM (p.payment_date - o.created_at)) / 60)::numeric AS avg_min, |
| | 27 | COUNT(DISTINCT o.order_id) AS total_orders |
| | 28 | FROM project.orders o |
| | 29 | JOIN project.payment p ON p.order_id = o.order_id |
| | 30 | JOIN project.app_user u ON u.user_id = o.user_id |
| | 31 | WHERE o.status = 'ПЛАТЕНА' |
| | 32 | GROUP BY u.user_id, u.first_name, u.last_name |
| | 33 | ), |
| | 34 | global_avg AS ( |
| | 35 | SELECT AVG(avg_min)::numeric AS g_avg FROM waiter_stats |
| | 36 | ) |
| | 37 | SELECT |
| | 38 | ws.uid, |
| | 39 | ws.wname, |
| | 40 | ROUND(ws.avg_min, 2), |
| | 41 | ROUND(ga.g_avg, 2), |
| | 42 | ws.total_orders, |
| | 43 | ( |
| | 44 | SELECT p.name::TEXT |
| | 45 | FROM project.order_item oi2 |
| | 46 | JOIN project.orders o2 ON o2.order_id = oi2.order_id |
| | 47 | JOIN project.product p ON p.product_id = oi2.product_id |
| | 48 | WHERE o2.user_id = ws.uid |
| | 49 | AND o2.status = 'ПЛАТЕНА' |
| | 50 | GROUP BY p.product_id, p.name |
| | 51 | ORDER BY SUM(oi2.quantity * oi2.unit_price) DESC |
| | 52 | LIMIT 1 |
| | 53 | ), |
| | 54 | ( |
| | 55 | SELECT SUM(oi3.quantity * oi3.unit_price)::numeric |
| | 56 | FROM project.order_item oi3 |
| | 57 | JOIN project.orders o3 ON o3.order_id = oi3.order_id |
| | 58 | JOIN project.product p3 ON p3.product_id = oi3.product_id |
| | 59 | WHERE o3.user_id = ws.uid |
| | 60 | AND o3.status = 'ПЛАТЕНА' |
| | 61 | AND p3.name = ( |
| | 62 | SELECT p4.name |
| | 63 | FROM project.order_item oi4 |
| | 64 | JOIN project.orders o4 ON o4.order_id = oi4.order_id |
| | 65 | JOIN project.product p4 ON p4.product_id = oi4.product_id |
| | 66 | WHERE o4.user_id = ws.uid AND o4.status = 'ПЛАТЕНА' |
| | 67 | GROUP BY p4.product_id, p4.name |
| | 68 | ORDER BY SUM(oi4.quantity * oi4.unit_price) DESC |
| | 69 | LIMIT 1 |
| | 70 | ) |
| | 71 | ) |
| | 72 | FROM waiter_stats ws, global_avg ga |
| | 73 | WHERE ws.avg_min < ga.g_avg |
| | 74 | ORDER BY 3 ASC; |
| | 75 | $$; |
| | 76 | }}} |
| | 77 | |
| | 78 | == Релациона алгебра == |
| | 79 | |
| | 80 | {{{ |
| | 81 | U(user_id, first_name, last_name) |
| | 82 | O(order_id, user_id, created_at, status) |
| | 83 | P(payment_id, order_id, payment_date) |
| | 84 | OI(order_id, product_id, quantity, unit_price) |
| | 85 | PR(product_id, name) |
| | 86 | |
| | 87 | J1 ← O ⨝ O.order_id = P.order_id P |
| | 88 | J2 ← J1 ⨝ O.user_id = U.user_id U |
| | 89 | F1 ← σ status='ПЛАТЕНА' (J2) |
| | 90 | G1 ← γ user_id, waiter_name; AVG((payment_date - created_at)/60) → avg_min, |
| | 91 | COUNT(DISTINCT order_id) → total_orders (F1) |
| | 92 | |
| | 93 | G2 ← γ ; AVG(avg_min) → g_avg (G1) |
| | 94 | |
| | 95 | F2 ← σ avg_min < g_avg (G1 × G2) |
| | 96 | |
| | 97 | J3 ← OI ⨝ O ⨝ PR |
| | 98 | F3 ← σ O.user_id = F2.user_id ∧ status='ПЛАТЕНА' (J3) |
| | 99 | G3 ← γ product_id, name; SUM(quantity * unit_price) → prod_rev (F3) |
| | 100 | TOP ← τ prod_rev DESC (G3) [LIMIT 1] |
| | 101 | |
| | 102 | R ← π user_id, waiter_name, avg_minutes, global_avg_minutes, |
| | 103 | total_orders, top_product, top_product_revenue (F2 ⨝ TOP) |
| | 104 | |
| | 105 | R_final ← τ avg_minutes ASC (R) |
| | 106 | }}} |