From 0c893df3b28d80dd92413bcd9c5d7c85001de8df Mon Sep 17 00:00:00 2001 From: Zurab Mdivani Date: Tue, 14 Oct 2025 19:18:04 +0200 Subject: [PATCH 1/5] Add employee table creation and data --- create_employees.sql | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/create_employees.sql b/create_employees.sql index e69de29..35ff036 100644 --- a/create_employees.sql +++ b/create_employees.sql @@ -0,0 +1,18 @@ +-- Create EMPLOYEE table for SExI system +CREATE TABLE IF NOT EXISTS memory.default.EMPLOYEE ( + employee_id TINYINT, + first_name VARCHAR, + last_name VARCHAR, + manager_id TINYINT +); + +-- Insert all employee data from hr/employee_index.csv +INSERT INTO memory.default.EMPLOYEE (employee_id, first_name, last_name, manager_id) VALUES (1, 'Ian', 'James', 4); +INSERT INTO memory.default.EMPLOYEE (employee_id, first_name, last_name, manager_id) VALUES (2, 'Umberto', 'Torrielli', 1); +INSERT INTO memory.default.EMPLOYEE (employee_id, first_name, last_name, manager_id) VALUES (3, 'Alex', 'Jacobson', 2); +INSERT INTO memory.default.EMPLOYEE (employee_id, first_name, last_name, manager_id) VALUES (4, 'Darren', 'Poynton', 2); +INSERT INTO memory.default.EMPLOYEE (employee_id, first_name, last_name, manager_id) VALUES (5, 'Tim', 'Beard', 2); +INSERT INTO memory.default.EMPLOYEE (employee_id, first_name, last_name, manager_id) VALUES (6, 'Gemma', 'Dodd', 1); +INSERT INTO memory.default.EMPLOYEE (employee_id, first_name, last_name, manager_id) VALUES (7, 'Lisa', 'Platten', 6); +INSERT INTO memory.default.EMPLOYEE (employee_id, first_name, last_name, manager_id) VALUES (8, 'Stefano', 'Camisaca', 2); +INSERT INTO memory.default.EMPLOYEE (employee_id, first_name, last_name, manager_id) VALUES (9, 'Andrea', 'Ghibaudi', 2); From 04c671ac74128b7be38334b564590aba366c009f Mon Sep 17 00:00:00 2001 From: Zurab Mdivani Date: Tue, 14 Oct 2025 19:24:40 +0200 Subject: [PATCH 2/5] Add expense table creation and data --- create_expenses.sql | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/create_expenses.sql b/create_expenses.sql index e69de29..a0fbefd 100644 --- a/create_expenses.sql +++ b/create_expenses.sql @@ -0,0 +1,29 @@ +-- Create EXPENSE table for SExI system +CREATE TABLE IF NOT EXISTS memory.default.EXPENSE ( + employee_id TINYINT, + unit_price DECIMAL(8, 2), + quantity TINYINT +); + +-- Insert expense data from finance/receipts_from_last_night directory + +-- drinkies.txt - Alex Jacobson +INSERT INTO memory.default.EXPENSE (employee_id, unit_price, quantity) VALUES (3, 6.50, 14); + +-- drinks.txt - Alex Jacobson +INSERT INTO memory.default.EXPENSE (employee_id, unit_price, quantity) VALUES (3, 11.00, 20); + +-- drinkss.txt - Alex Jacobson +INSERT INTO memory.default.EXPENSE (employee_id, unit_price, quantity) VALUES (3, 22.00, 18); + +-- duh_i_think_i_got_too_many.txt - Alex Jacobson +INSERT INTO memory.default.EXPENSE (employee_id, unit_price, quantity) VALUES (3, 13.00, 75); + +-- i_got_lost_on_the_way_home_and_now_im_in_mexico.txt - Andrea Ghibaudi +INSERT INTO memory.default.EXPENSE (employee_id, unit_price, quantity) VALUES (9, 300.00, 1); + +-- ubers.txt - Darren Poynton +INSERT INTO memory.default.EXPENSE (employee_id, unit_price, quantity) VALUES (4, 40.00, 9); + +-- we_stopped_for_a_kebabs.txt - Umberto Torrielli +INSERT INTO memory.default.EXPENSE (employee_id, unit_price, quantity) VALUES (2, 17.50, 4); From c19b4c9a3c2445b8b201045d8f2b824567613011 Mon Sep 17 00:00:00 2001 From: Zurab Mdivani Date: Tue, 14 Oct 2025 19:40:12 +0200 Subject: [PATCH 3/5] Add manager cycle detection query --- find_manager_cycles.sql | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/find_manager_cycles.sql b/find_manager_cycles.sql index e69de29..823784f 100644 --- a/find_manager_cycles.sql +++ b/find_manager_cycles.sql @@ -0,0 +1,33 @@ +-- Find cycles in employee-manager relationships +-- Detects circular approval chains where employees approve each other's expenses + +WITH RECURSIVE manager_chain (employee_id, manager_id, chain, start_employee, depth) AS ( + SELECT + employee_id, + manager_id, + CAST(employee_id AS VARCHAR), + employee_id, + 1 + FROM memory.default.EMPLOYEE + WHERE manager_id IS NOT NULL + + UNION ALL + + SELECT + e.employee_id, + e.manager_id, + mc.chain || ',' || CAST(e.employee_id AS VARCHAR), + mc.start_employee, + mc.depth + 1 + FROM memory.default.EMPLOYEE e + INNER JOIN manager_chain mc ON e.employee_id = mc.manager_id + WHERE e.manager_id IS NOT NULL + AND mc.depth < 20 + AND POSITION(CAST(e.employee_id AS VARCHAR) IN mc.chain) = 0 +) +SELECT DISTINCT + start_employee as employee_id, + chain || ',' || CAST(manager_id AS VARCHAR) as cycle +FROM manager_chain +WHERE manager_id = start_employee +ORDER BY employee_id; From 3f8e2a08eabb5d5dfe370212f00b7f8eb9314e8b Mon Sep 17 00:00:00 2001 From: Zurab Mdivani Date: Tue, 14 Oct 2025 19:43:13 +0200 Subject: [PATCH 4/5] Add query to find employees exceeding expense limit --- calculate_largest_expensors.sql | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/calculate_largest_expensors.sql b/calculate_largest_expensors.sql index e69de29..8b4cf53 100644 --- a/calculate_largest_expensors.sql +++ b/calculate_largest_expensors.sql @@ -0,0 +1,21 @@ +-- Report employees who have expensed more than 1000 +-- Shows employee details, their manager, and total expenses in descending order + +SELECT + e.employee_id, + e.first_name || ' ' || e.last_name as employee_name, + e.manager_id, + m.first_name || ' ' || m.last_name as manager_name, + SUM(ex.unit_price * ex.quantity) as total_expensed_amount +FROM memory.default.EMPLOYEE e +INNER JOIN memory.default.EXPENSE ex ON e.employee_id = ex.employee_id +LEFT JOIN memory.default.EMPLOYEE m ON e.manager_id = m.employee_id +GROUP BY + e.employee_id, + e.first_name, + e.last_name, + e.manager_id, + m.first_name, + m.last_name +HAVING SUM(ex.unit_price * ex.quantity) > 1000 +ORDER BY total_expensed_amount DESC; From 5d5d58b8b63b4cb1c61d76d8334267f05687e9de Mon Sep 17 00:00:00 2001 From: Zurab Mdivani Date: Tue, 14 Oct 2025 19:50:52 +0200 Subject: [PATCH 5/5] Add largest expensors and payment plans queries --- generate_supplier_payment_plans.sql | 53 +++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/generate_supplier_payment_plans.sql b/generate_supplier_payment_plans.sql index e69de29..2e68ff0 100644 --- a/generate_supplier_payment_plans.sql +++ b/generate_supplier_payment_plans.sql @@ -0,0 +1,53 @@ +-- Generate monthly payment plan for suppliers +-- Creates a payment schedule showing monthly payments to fully pay invoices before due dates + +WITH supplier_totals AS ( + -- Calculate total owed per supplier and months until furthest due date + SELECT + s.supplier_id, + s.name as supplier_name, + SUM(i.invoice_ammount) as total_owed, + MAX(i.due_date) as final_due_date, + CAST(MONTH(MAX(i.due_date)) - MONTH(CURRENT_DATE) + + (YEAR(MAX(i.due_date)) - YEAR(CURRENT_DATE)) * 12 AS INTEGER) as months_to_pay + FROM memory.default.SUPPLIER s + INNER JOIN memory.default.INVOICE i ON s.supplier_id = i.supplier_id + GROUP BY s.supplier_id, s.name +), +payment_months AS ( + -- Generate sequence of payment months for each supplier + SELECT + supplier_id, + supplier_name, + total_owed, + months_to_pay, + month_num + FROM supplier_totals + CROSS JOIN UNNEST(SEQUENCE(1, GREATEST(months_to_pay, 1))) AS t(month_num) +), +payments AS ( + -- Calculate payment amount and balance for each month + SELECT + supplier_id, + supplier_name, + CASE + WHEN month_num < months_to_pay THEN ROUND(total_owed / months_to_pay, 2) + ELSE total_owed - (ROUND(total_owed / months_to_pay, 2) * (months_to_pay - 1)) + END as payment_amount, + total_owed - (ROUND(total_owed / months_to_pay, 2) * (month_num - 1)) as balance_before, + month_num, + LAST_DAY_OF_MONTH(DATE_ADD('month', month_num - 1, CURRENT_DATE)) as payment_date_actual + FROM payment_months +) +SELECT + supplier_id, + supplier_name, + payment_amount, + balance_before - payment_amount as balance_outstanding, + CASE + WHEN month_num = 1 THEN 'End of this month' + WHEN month_num = 2 THEN 'End of next month' + ELSE 'End of the month after' + END as payment_date +FROM payments +ORDER BY supplier_id, month_num;