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
64 changes: 64 additions & 0 deletions calculate_largest_expensors.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
-- When interacting with trino, `USE` the `memory.default` catalogue.schema.
USE memory.default;

-- Main query to identify employees who expensed more than 1000
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 EMPLOYEE e
LEFT JOIN EXPENSE exp ON e.employee_id = exp.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;

-- Verify expense calculations for all employees
SELECT
e.employee_id,
CONCAT(e.first_name, ' ', e.last_name) AS employee_name,
COUNT(exp.employee_id) AS number_of_receipts,
COALESCE(SUM(exp.unit_price * exp.quantity), 0) AS total_expensed_amount,
CASE
WHEN COALESCE(SUM(exp.unit_price * exp.quantity), 0) > 1000 THEN 'EXCEEDS LIMIT'
ELSE 'WITHIN LIMIT'
END AS status
FROM EMPLOYEE e
LEFT JOIN EXPENSE exp ON e.employee_id = exp.employee_id
GROUP BY
e.employee_id,
e.first_name,
e.last_name
ORDER BY total_expensed_amount DESC;



-- Alternative implementation using Common Table Expression for clarity
-- This approach separates expense calculation from employee details
WITH EmployeeExpenses AS (
-- Calculate total expenses for each employee
SELECT
employee_id,
SUM(unit_price * quantity) AS total_expensed_amount
FROM EXPENSE
GROUP BY employee_id
HAVING SUM(unit_price * quantity) > 1000
)
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,
ee.total_expensed_amount
FROM EmployeeExpenses ee
JOIN EMPLOYEE e ON ee.employee_id = e.employee_id
LEFT JOIN EMPLOYEE m ON e.manager_id = m.employee_id
ORDER BY ee.total_expensed_amount DESC;
52 changes: 52 additions & 0 deletions create_employees.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
-- When interacting with trino, `USE` the `memory.default` catalogue.schema.
USE memory.default;

-- Drop table if it already exists
DROP TABLE IF EXISTS EMPLOYEE;

-- Create the EMPLOYEE table with appropriate data types
CREATE TABLE EMPLOYEE (
employee_id TINYINT,
first_name VARCHAR,
last_name VARCHAR,
job_title VARCHAR,
manager_id TINYINT
);

-- Manually insert the employee data as Trino doesn't support direct CSV import
INSERT INTO EMPLOYEE (employee_id, first_name, last_name, job_title, manager_id) 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);

-- Verify the table was created successfully
SHOW TABLES FROM memory.default;

-- Check table structure
DESCRIBE memory.default.EMPLOYEE;

-- Verify all data was inserted correctly
SELECT * FROM EMPLOYEE ORDER BY employee_id;

-- Check for any invalid manager references (managers that don't exist as employees)
SELECT e.employee_id, e.first_name, e.last_name, e.manager_id
FROM EMPLOYEE e
LEFT JOIN EMPLOYEE m ON e.manager_id = m.employee_id
WHERE e.manager_id IS NOT NULL AND m.employee_id IS NULL;

-- Display employee hierarchy for verification
SELECT
e.employee_id,
CONCAT(e.first_name, ' ', e.last_name) AS employee_name,
e.job_title,
e.manager_id,
CONCAT(m.first_name, ' ', m.last_name) AS manager_name
FROM EMPLOYEE e
LEFT JOIN EMPLOYEE m ON e.manager_id = m.employee_id
ORDER BY e.employee_id;
60 changes: 60 additions & 0 deletions create_expenses.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
-- When interacting with trino, `USE` the `memory.default` catalogue.schema.
USE memory.default;

-- Drop table if it already exists
DROP TABLE IF EXISTS EXPENSE;

-- Create the EXPENSE table with appropriate data types
CREATE TABLE EXPENSE (
employee_id TINYINT,
unit_price DECIMAL(8, 2),
quantity TINYINT
);

-- Manually insert expense data from finance/receipts_from_last_night/*.txt files
INSERT INTO EXPENSE (employee_id, unit_price, quantity) VALUES
(3, 6.50, 14),
(3, 11.00, 20),
(3, 22.00, 18),
(3, 13.00, 75),
(9, 300.00, 1),
(4, 40.00, 9),
(2, 17.50, 4);

-- Verify the table was created successfully
SHOW TABLES FROM memory.default;

-- Check table structure
DESCRIBE memory.default.EXPENSE;

-- Verify all data was inserted correctly
SELECT * FROM EXPENSE ORDER BY employee_id, unit_price;

-- Check for any invalid employee references (expenses for employees that don't exist)
SELECT e.employee_id, e.unit_price, e.quantity
FROM EXPENSE e
LEFT JOIN EMPLOYEE emp ON e.employee_id = emp.employee_id
WHERE emp.employee_id IS NULL;

-- Display expenses with employee details for verification
SELECT
e.employee_id,
CONCAT(emp.first_name, ' ', emp.last_name) AS employee_name,
emp.job_title,
e.unit_price,
e.quantity,
(e.unit_price * e.quantity) AS total_amount
FROM EXPENSE e
LEFT JOIN EMPLOYEE emp ON e.employee_id = emp.employee_id
ORDER BY e.employee_id, e.unit_price;

-- Calculate total expenses per employee
SELECT
e.employee_id,
CONCAT(emp.first_name, ' ', emp.last_name) AS employee_name,
COUNT(*) AS number_of_receipts,
SUM(e.unit_price * e.quantity) AS total_expensed_amount
FROM EXPENSE e
LEFT JOIN EMPLOYEE emp ON e.employee_id = emp.employee_id
GROUP BY e.employee_id, emp.first_name, emp.last_name
ORDER BY total_expensed_amount DESC;
87 changes: 87 additions & 0 deletions create_invoices.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
-- When interacting with trino, `USE` the `memory.default` catalogue.schema.
USE memory.default;

-- Drop tables if they already exist
DROP TABLE IF EXISTS INVOICE;
DROP TABLE IF EXISTS SUPPLIER;

-- Create the SUPPLIER table with appropriate data types
CREATE TABLE SUPPLIER (
supplier_id TINYINT,
name VARCHAR
);

-- Insert suppliers sorted alphabetically by name
INSERT INTO SUPPLIER (supplier_id, name) VALUES
(1, 'Catering Plus'),
(2, 'Dave''s Discos'),
(3, 'Entertainment tonight'),
(4, 'Ice Ice Baby'),
(5, 'Party Animals');

-- Create the INVOICE table with appropriate data types as specified in requirements
CREATE TABLE INVOICE (
supplier_id TINYINT,
invoice_amount DECIMAL(8, 2),
due_date DATE
);

-- Manually insert invoice data from finance/invoices_due/*.txt files
INSERT INTO INVOICE (supplier_id, invoice_amount, due_date) VALUES
(1, 2000.00, DATE '2025-02-28'),
(1, 1500.00, DATE '2025-03-31'),
(2, 500.00, DATE '2025-01-31'),
(3, 6000.00, DATE '2025-03-31'),
(4, 4000.00, DATE '2025-06-30'),
(5, 6000.00, DATE '2025-03-31');

-- Verify the tables were created successfully
SHOW TABLES FROM memory.default;

-- Check table structures
DESCRIBE memory.default.SUPPLIER;
DESCRIBE memory.default.INVOICE;

-- Verify all supplier data was inserted correctly
SELECT * FROM SUPPLIER ORDER BY supplier_id;

-- Verify all invoice data was inserted correctly
SELECT * FROM INVOICE ORDER BY supplier_id, due_date;

-- Check for any invalid supplier references (invoices for suppliers that don't exist)
SELECT i.supplier_id, i.invoice_amount, i.due_date
FROM INVOICE i
LEFT JOIN SUPPLIER s ON i.supplier_id = s.supplier_id
WHERE s.supplier_id IS NULL;

-- Display invoices with supplier details for verification
SELECT
i.supplier_id,
s.name AS supplier_name,
i.invoice_amount,
i.due_date
FROM INVOICE i
LEFT JOIN SUPPLIER s ON i.supplier_id = s.supplier_id
ORDER BY i.supplier_id, i.due_date;

-- Calculate total invoices per supplier
SELECT
i.supplier_id,
s.name AS supplier_name,
COUNT(*) AS number_of_invoices,
SUM(i.invoice_amount) AS total_invoice_amount
FROM INVOICE i
LEFT JOIN SUPPLIER s ON i.supplier_id = s.supplier_id
GROUP BY i.supplier_id, s.name
ORDER BY i.supplier_id;

-- Verify all due dates are last day of the month
SELECT
supplier_id,
invoice_amount,
due_date,
CASE
WHEN due_date = LAST_DAY_OF_MONTH(due_date) THEN 'Valid'
ELSE 'Invalid - not last day of month'
END AS date_validation
FROM INVOICE;
48 changes: 48 additions & 0 deletions find_manager_cycles.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
-- When interacting with trino, `USE` the `memory.default` catalogue.schema.
USE memory.default;

-- This query identifies cycles in the employee-manager hierarchy
WITH RECURSIVE manager_chain (employee_id, current_manager, path, depth, start_employee) AS (
-- Start with each employee and their manager
SELECT
employee_id,
manager_id AS current_manager,
CAST(employee_id AS VARCHAR) AS path,
1 AS depth,
employee_id AS start_employee
FROM EMPLOYEE
WHERE manager_id IS NOT NULL

UNION ALL

-- Follow the management chain
SELECT
mc.employee_id,
e.manager_id AS current_manager,
CONCAT(mc.path, ',', CAST(e.employee_id AS VARCHAR)) AS path,
mc.depth + 1,
mc.start_employee
FROM manager_chain mc
JOIN EMPLOYEE e ON mc.current_manager = e.employee_id
WHERE mc.depth < 10 -- Prevent infinite loops
AND e.manager_id IS NOT NULL -- Only continue if there's a next manager
AND e.employee_id != mc.start_employee -- Stop before we would revisit the starting employee
)

SELECT DISTINCT
mc.start_employee AS employee_id,
CONCAT(mc.path, ',', CAST(mc.current_manager AS VARCHAR)) AS cycle
FROM manager_chain mc
WHERE mc.current_manager = mc.start_employee -- The current manager is the same as where we started
ORDER BY employee_id;

-- Show employee hierarchy for verification
SELECT
e.employee_id,
CONCAT(e.first_name, ' ', e.last_name) AS employee_name,
e.job_title,
e.manager_id,
CONCAT(m.first_name, ' ', m.last_name) AS manager_name
FROM EMPLOYEE e
LEFT JOIN EMPLOYEE m ON e.manager_id = m.employee_id
ORDER BY e.employee_id;
68 changes: 68 additions & 0 deletions generate_supplier_payment_plans.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
-- When interacting with trino, `USE` the `memory.default` catalogue.schema.
USE memory.default;

-- Main query to generate supplier payment plans with $1500 flat monthly payments
WITH supplier_totals AS (
-- Calculate total amount due for each supplier across all invoices
SELECT
s.supplier_id,
s.name AS supplier_name,
SUM(i.invoice_amount) AS total_due
FROM SUPPLIER s
JOIN INVOICE i ON s.supplier_id = i.supplier_id
GROUP BY s.supplier_id, s.name
),
payment_installments AS (
-- Generate payment installments for each supplier
SELECT
st.supplier_id,
st.supplier_name,
st.total_due,
-- Calculate number of payments needed (total_due / 1500, rounded up)
CEIL(st.total_due / 1500.00) AS payment_count,
-- Generate payment numbers (1, 2, 3, etc.)
payment_number
FROM supplier_totals st
CROSS JOIN UNNEST(sequence(1, CAST(CEIL(st.total_due / 1500.00) AS BIGINT))) AS t(payment_number)
),
calculated_payments AS (
-- Calculate payment amounts and dates
SELECT
pi.supplier_id,
pi.supplier_name,
pi.total_due,
-- Payment amount is $1500, except for final payment which is remaining balance
CASE
WHEN pi.payment_number = pi.payment_count THEN
pi.total_due - (1500.00 * (pi.payment_number - 1))
ELSE 1500.00
END AS payment_amount,
-- Payment date is last day of month, starting from current month
DATE_ADD('month', pi.payment_number - 1, LAST_DAY_OF_MONTH(CURRENT_DATE)) AS payment_date,
pi.payment_number
FROM payment_installments pi
)
-- Final result with running balance calculation
SELECT
cp.supplier_id,
cp.supplier_name,
ROUND(cp.payment_amount, 2) AS payment_amount,
ROUND(cp.total_due - SUM(cp.payment_amount) OVER (
PARTITION BY cp.supplier_id
ORDER BY cp.payment_date
), 2) AS balance_outstanding,
cp.payment_date
FROM calculated_payments cp
ORDER BY cp.supplier_name, cp.payment_date;

-- Verify payment plan calculations
SELECT
s.supplier_id,
s.name AS supplier_name,
COUNT(*) AS invoice_count,
SUM(i.invoice_amount) AS total_invoice_amount,
CEIL(SUM(i.invoice_amount) / 1500.00) AS estimated_payments_needed
FROM SUPPLIER s
LEFT JOIN INVOICE i ON s.supplier_id = i.supplier_id
GROUP BY s.supplier_id, s.name
ORDER BY s.supplier_id;