diff --git a/calculate_largest_expensors.sql b/calculate_largest_expensors.sql index e69de29..1a9132a 100644 --- a/calculate_largest_expensors.sql +++ b/calculate_largest_expensors.sql @@ -0,0 +1,20 @@ +USE memory.default; + +-- This query reports employees whose total expensed_amount exceeds 1000. +-- The expensed_amount is computed as unit_price * quantity for each expense. +-- We join the EXPENSE and EMPLOYEE tables and also fetch the manager's name via a self-join. +SELECT + e.employee_id, + CONCAT(e.first_name, ' ', e.last_name) AS employee_name, + e.manager_id, + CONCAT(m.first_name, ' ', m.last_name) AS manager_name, + SUM(exp.unit_price * exp.quantity) AS total_expensed_amount +FROM EXPENSE exp +JOIN EMPLOYEE e ON exp.employee_id = e.employee_id +LEFT JOIN 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(exp.unit_price * exp.quantity) > 1000 +ORDER BY total_expensed_amount DESC; + +-- Comment: This query aggregates all expenses per employee and filters out those who expensed more than 1000. diff --git a/create_employees.sql b/create_employees.sql index e69de29..6449ead 100644 --- a/create_employees.sql +++ b/create_employees.sql @@ -0,0 +1,25 @@ +USE memory.default; + +-- Creating EMPLOYEE table using data from hr/employee_index.csv file +CREATE TABLE EMPLOYEE ( + employee_id TINYINT, + first_name VARCHAR, + last_name VARCHAR, + job_title VARCHAR, + manager_id TINYINT +) +COMMENT 'Employee table using data from hr/employee_index.csv file'; + +-- Inserting data into EMPLOYEE table +INSERT INTO EMPLOYEE VALUES + (1, 'Ian', 'James', 'CEO', 4), + (2, 'Umberto', 'Torrielli', 'CSO', 1), + (3, 'Alex', 'Jacobson', 'MD EMEA', 2), + (4, 'Darren', 'Poynton', 'CFO', 2), + (5, 'Tim', 'Beard', 'MD APAC', 2), + (6, 'Gemma', 'Dodd', 'COS', 1), + (7, 'Lisa', 'Platten', 'CHR', 6), + (8, 'Stefano', 'Camisaca', 'GM Activation', 2), + (9, 'Andrea', 'Ghibaudi', 'MD NAM', 2); + +-- Comment: Data inserted as per employee_index.csv. diff --git a/create_expenses.sql b/create_expenses.sql index e69de29..3823fe9 100644 --- a/create_expenses.sql +++ b/create_expenses.sql @@ -0,0 +1,42 @@ +USE memory.default; + +-- Creating EXPENSE table to store last night's receipts. +CREATE TABLE EXPENSE ( + employee_id TINYINT, + unit_price DECIMAL(8,2), + quantity TINYINT +) +COMMENT 'Expense table loaded from finance/receipts_from_last_night files'; + +-- Inserting receipt data from finance/receipts_from_last_night + +-- From drinkies.txt: +-- Employee: Alex Jacobson (employee_id: 3), Unit Price: 6.50, Quantity: 14 +INSERT INTO EXPENSE VALUES (3, 6.50, 14); + +-- From drinks.txt: +-- Employee: Alex Jacobson (employee_id: 3), Unit Price: 11.00, Quantity: 20 +INSERT INTO EXPENSE VALUES (3, 11.00, 20); + +-- From drinkss.txt: +-- Employee: Alex Jacobson (employee_id: 3), record incomplete (no unit price/quantity provided). +-- We set unit_price and quantity to 0 to indicate missing data. +INSERT INTO EXPENSE VALUES (3, 0.00, 0); + +-- From duh_i_think_i_got_too_many.txt: +-- Employee: Alex Jacobson (employee_id: 3), Unit Price: 13.00, Quantity: 75 +INSERT INTO EXPENSE VALUES (3, 13.00, 75); + +-- From i_got_lost_on_the_way_home_and_now_im_in_mexico.txt: +-- Employee: Andrea Ghibaudi (employee_id: 9), Unit Price: 300, Quantity: 1 +INSERT INTO EXPENSE VALUES (9, 300.00, 1); + +-- From ubers.txt: +-- Employee: Darren Poynton (employee_id: 4), Unit Price: 40.00, Quantity: 9 +INSERT INTO EXPENSE VALUES (4, 40.00, 9); + +-- From we_stopped_for_a_kebabs.txt: +-- Employee: Umberto Torrielli (employee_id: 2), Unit Price: 17.50, Quantity: 4 +INSERT INTO EXPENSE VALUES (2, 17.50, 4); + +-- Comment: Using direct inserts to simulate the imported receipts from text files. diff --git a/create_invoices.sql b/create_invoices.sql index e69de29..46fd735 100644 --- a/create_invoices.sql +++ b/create_invoices.sql @@ -0,0 +1,58 @@ +USE memory.default; + +-- Creating the INVOICE table to store supplier invoice details. +CREATE TABLE INVOICE ( + supplier_id TINYINT, + invoice_ammount DECIMAL(8,2), + due_date DATE +) +COMMENT 'Invoice table loaded from finance/invoices_due files'; + +-- Creating the SUPPLIER table to store supplier details. +CREATE TABLE SUPPLIER ( + supplier_id TINYINT, + name VARCHAR +) +COMMENT 'Supplier table derived from invoice file company names'; + +-- Inserting supplier data. +-- Suppliers sorted alphabetically: +-- 1: Catering Plus +-- 2: Dave''s Discos +-- 3: Entertainment tonight +-- 4: Ice Ice Baby +-- 5: Party Animals + +INSERT INTO SUPPLIER VALUES + (1, 'Catering Plus'), + (2, 'Dave''s Discos'), + (3, 'Entertainment tonight'), + (4, 'Ice Ice Baby'), + (5, 'Party Animals'); + +-- Inserting invoice data from invoice files: +-- awesome_animals.txt: +-- Company Name: Party Animals, Invoice Amount: 6000, Due Date: 3 months from now (assume 2025-07-31) +INSERT INTO INVOICE VALUES (5, 6000.00, DATE '2025-07-31'); + +-- brilliant_bottles.txt: +-- Company Name: Catering Plus, Invoice Amount: 2000, Due Date: 2 months from now (assume 2025-06-30) +INSERT INTO INVOICE VALUES (1, 2000.00, DATE '2025-06-30'); + +-- crazy_catering.txt: +-- Company Name: Catering Plus, Invoice Amount: 1500, Due Date: 3 months from now (assume 2025-07-31) +INSERT INTO INVOICE VALUES (1, 1500.00, DATE '2025-07-31'); + +-- disco_dj.txt: +-- Company Name: Dave's Discos, Invoice Amount: 500, Due Date: 1 month from now (assume 2025-05-31) +INSERT INTO INVOICE VALUES (2, 500.00, DATE '2025-05-31'); + +-- excellent_entertainment.txt: +-- Company Name: Entertainment tonight, Invoice Amount: 6000, Due Date: 3 months from now (assume 2025-07-31) +INSERT INTO INVOICE VALUES (3, 6000.00, DATE '2025-07-31'); + +-- fantastic_ice_sculptures.txt: +-- Company Name: Ice Ice Baby, Invoice Amount: 4000, Due Date: 6 months from now (assume 2025-10-31) +INSERT INTO INVOICE VALUES (4, 4000.00, DATE '2025-10-31'); + +-- Comment: Due dates set to the last day of the respective month based on "n months from now". diff --git a/find_manager_cycles.sql b/find_manager_cycles.sql index e69de29..3aa689c 100644 --- a/find_manager_cycles.sql +++ b/find_manager_cycles.sql @@ -0,0 +1,31 @@ +USE memory.default; + +-- This query attempts to detect cycles in the manager relationships (i.e., employees approving each other's expenses). +-- We use a recursive Common Table Expression (CTE) to build paths from each employee up the management chain. +-- The resulting path is returned as a comma-separated list of employee_ids indicating the cycle. +WITH RECURSIVE manager_paths(employee_id, manager_id, path) AS ( + -- Base step: start with each employee + SELECT + employee_id, + manager_id, + CAST(employee_id AS VARCHAR) AS path + FROM EMPLOYEE + UNION ALL + -- Recursive step: join with EMPLOYEE to follow the manager chain + SELECT + mp.employee_id, + e.manager_id, + CONCAT(mp.path, ',', CAST(e.manager_id AS VARCHAR)) + FROM manager_paths mp + JOIN EMPLOYEE e ON mp.manager_id = e.employee_id + -- Prevent cycles from repeating nodes in the path + WHERE strpos(mp.path, CAST(e.manager_id AS VARCHAR)) = 0 +) +-- Select paths where the cycle is closed; for instance, where the current manager_id appears in the path. +SELECT + employee_id, + path AS manager_cycle +FROM manager_paths +WHERE strpos(path, CAST(manager_id AS VARCHAR)) > 0; + +-- Comment: This recursive CTE builds the chain and then filters for cycles. diff --git a/generate_supplier_payment_plans.sql b/generate_supplier_payment_plans.sql index e69de29..c904f08 100644 --- a/generate_supplier_payment_plans.sql +++ b/generate_supplier_payment_plans.sql @@ -0,0 +1,44 @@ +USE memory.default; + +-- Generate a monthly supplier payment plan. +-- For each supplier, we assume a fixed maximum monthly payment of 1500. +-- The total number of payments is calculated as CEIL(total_outstanding / 1500). +-- Payment dates are generated by adding an offset in months to the end-of-current-month date. +-- This approach uses UNNEST and sequence() to simulate the recurrence without a recursive CTE. + +WITH supplier_totals AS ( + -- Calculate total outstanding per supplier from all invoices + SELECT + s.supplier_id, + s.name AS supplier_name, + SUM(i.invoice_ammount) AS total_outstanding + FROM SUPPLIER s + JOIN INVOICE i ON s.supplier_id = i.supplier_id + GROUP BY s.supplier_id, s.name +), +supplier_payments AS ( + SELECT + supplier_id, + supplier_name, + total_outstanding, + CAST(CEIL(total_outstanding / 1500.0) AS INTEGER) AS num_payments + FROM supplier_totals +) +SELECT + sp.supplier_id, + sp.supplier_name, + -- Determine payment amount: For all but the last payment, it's 1500, otherwise the remaining balance. + CASE + WHEN month_offset < sp.num_payments - 1 THEN 1500.00 + ELSE sp.total_outstanding - 1500.00 * (sp.num_payments - 1) + END AS payment_amount, + -- Calculate the remaining balance after the payment at this step + sp.total_outstanding - 1500.00 * month_offset AS balance_outstanding, + -- Payment date: start at the end of the current month and add month_offset months + CAST(date_add('month', month_offset, + CAST(date_trunc('month', CURRENT_DATE) + interval '1' month - interval '1' day AS DATE)) + AS DATE) AS payment_date +FROM supplier_payments sp, + -- Generate a series [0, num_payments-1] per supplier to represent each payment. + UNNEST(sequence(0, sp.num_payments - 1)) AS t(month_offset) +ORDER BY sp.supplier_id, payment_date;