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; 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); 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); 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; 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;