Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions calculate_largest_expensors.sql
Original file line number Diff line number Diff line change
@@ -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;
18 changes: 18 additions & 0 deletions create_employees.sql
Original file line number Diff line number Diff line change
@@ -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);
29 changes: 29 additions & 0 deletions create_expenses.sql
Original file line number Diff line number Diff line change
@@ -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);
33 changes: 33 additions & 0 deletions find_manager_cycles.sql
Original file line number Diff line number Diff line change
@@ -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;
53 changes: 53 additions & 0 deletions generate_supplier_payment_plans.sql
Original file line number Diff line number Diff line change
@@ -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;