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
Empty file added -v
Empty file.
23 changes: 23 additions & 0 deletions calculate_largest_expensors.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
USE memory.default;

SELECT
e.employee_id,
CONCAT(e.first_name, ' ', e.last_name) AS employee_name,
e.manager_id,
CONCAT(COALESCE(m.first_name, ''), ' ', COALESCE(m.last_name, '')) AS manager_name,
ROUND(SUM(exp.unit_price * exp.quantity), 2) AS total_expensed_amount
FROM
SEXI.EMPLOYEE e
LEFT JOIN SEXI.EMPLOYEE m ON e.manager_id = m.employee_id
INNER JOIN SEXI.EXPENSE exp ON e.employee_id = exp.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;
33 changes: 33 additions & 0 deletions create_employees.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
-- Use the memory catalog and default schema
USE memory.default;

-- Create the SEXI schema if it doesn't exist
CREATE SCHEMA IF NOT EXISTS SEXI;

-- Drop the EMPLOYEE table if it exists
DROP TABLE IF EXISTS SEXI.EMPLOYEE;

-- Create the EMPLOYEE table with data, casting employee_id and manager_id to TINYINT
CREATE TABLE SEXI.EMPLOYEE AS
SELECT
CAST(employee_id AS TINYINT) AS employee_id,
first_name,
last_name,
job_title,
CAST(manager_id AS TINYINT) AS manager_id
FROM
(
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)
) AS t (employee_id, first_name, last_name, job_title, manager_id);

-- Print out the result
SELECT * FROM SEXI.EMPLOYEE;
34 changes: 34 additions & 0 deletions create_expenses.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
USE memory.default;

-- Create the SEXI schema if it doesn't exist
CREATE SCHEMA IF NOT EXISTS SEXI;

-- Create the EXPENSE table if it doesn't exist
CREATE TABLE IF NOT EXISTS SEXI.EXPENSE (
employee_id TINYINT,
unit_price DECIMAL(8, 2),
quantity TINYINT
);

-- Insert data into SEXI.EXPENSE using the VALUES clause and an INNER JOIN
INSERT INTO SEXI.EXPENSE (employee_id, unit_price, quantity)
SELECT
emp.employee_id,
rec.unit_price,
rec.quantity
FROM
(VALUES
('Alex', 'Jacobson', 6.50, 14),
('Alex', 'Jacobson', 11.00, 20),
('Alex', 'Jacobson', 22.00, 18),
('Alex', 'Jacobson', 13.00, 75),
('Andrea', 'Ghibaudi', 300.00, 1),
('Darren', 'Poynton', 40.00, 9),
('Umberto', 'Torrielli', 17.50, 4)
) AS rec (first_name, last_name, unit_price, quantity)
INNER JOIN SEXI.EMPLOYEE emp
ON UPPER(emp.first_name) = UPPER(rec.first_name)
AND UPPER(emp.last_name) = UPPER(rec.last_name);

-- Print SEXI.EXPENSE to check the solution
SELECT * FROM SEXI.EXPENSE;
66 changes: 66 additions & 0 deletions create_invoices.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
-- Use the memory catalog and default schema
USE memory.default;

-- Create the SEXI schema if it doesn't exist
CREATE SCHEMA IF NOT EXISTS SEXI;

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

-- Create the SUPPLIER table
CREATE TABLE SEXI.SUPPLIER (
supplier_id TINYINT,
name VARCHAR
);

-- Insert suppliers into the SUPPLIER table
INSERT INTO SEXI.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
CREATE TABLE SEXI.INVOICE (
supplier_id TINYINT,
invoice_amount DECIMAL(8, 2),
due_date DATE
);

-- Base date for calculations (assuming current date is '2024-11-01')
-- We'll hardcode this date in each calculation

-- Insert invoices into the INVOICE table
INSERT INTO SEXI.INVOICE (supplier_id, invoice_amount, due_date)
SELECT
(SELECT supplier_id FROM SEXI.SUPPLIER WHERE name = 'Party Animals') AS supplier_id,
6000.00 AS invoice_amount,
date_trunc('month', DATE '2024-11-01' + INTERVAL '4' MONTH) - INTERVAL '1' DAY AS due_date
UNION ALL
SELECT
(SELECT supplier_id FROM SEXI.SUPPLIER WHERE name = 'Catering Plus') AS supplier_id,
2000.00 AS invoice_amount,
date_trunc('month', DATE '2024-11-01' + INTERVAL '3' MONTH) - INTERVAL '1' DAY AS due_date
UNION ALL
SELECT
(SELECT supplier_id FROM SEXI.SUPPLIER WHERE name = 'Catering Plus') AS supplier_id,
1500.00 AS invoice_amount,
date_trunc('month', DATE '2024-11-01' + INTERVAL '4' MONTH) - INTERVAL '1' DAY AS due_date
UNION ALL
SELECT
(SELECT supplier_id FROM SEXI.SUPPLIER WHERE name = 'Dave''s Discos') AS supplier_id,
500.00 AS invoice_amount,
date_trunc('month', DATE '2024-11-01' + INTERVAL '2' MONTH) - INTERVAL '1' DAY AS due_date
UNION ALL
SELECT
(SELECT supplier_id FROM SEXI.SUPPLIER WHERE name = 'Entertainment tonight') AS supplier_id,
6000.00 AS invoice_amount,
date_trunc('month', DATE '2024-11-01' + INTERVAL '4' MONTH) - INTERVAL '1' DAY AS due_date
UNION ALL
SELECT
(SELECT supplier_id FROM SEXI.SUPPLIER WHERE name = 'Ice Ice Baby') AS supplier_id,
4000.00 AS invoice_amount,
date_trunc('month', DATE '2024-11-01' + INTERVAL '7' MONTH) - INTERVAL '1' DAY AS due_date;
35 changes: 35 additions & 0 deletions find_manager_cycles.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
USE memory.default;

WITH RECURSIVE manager_cycles (employee_id, manager_id, path, visited) AS (
-- Anchor member
SELECT
employee_id,
manager_id,
CAST(employee_id AS VARCHAR) AS path,
CAST(employee_id AS VARCHAR) AS visited
FROM
sexi.EMPLOYEE

UNION ALL

-- Recursive member
SELECT
mc.employee_id,
e.manager_id,
CONCAT(mc.path, '->', CAST(e.manager_id AS VARCHAR)) AS path,
CONCAT(mc.visited, ',', CAST(e.manager_id AS VARCHAR)) AS visited
FROM
manager_cycles mc
JOIN sexi.EMPLOYEE e ON mc.manager_id = e.employee_id
WHERE
POSITION(',' || CAST(e.manager_id AS VARCHAR) || ',' IN ',' || mc.visited || ',') = 0
AND e.manager_id IS NOT NULL
)

SELECT
employee_id AS cyclic_employee_id,
path AS cycle_path
FROM
manager_cycles
WHERE
POSITION(',' || CAST(manager_id AS VARCHAR) || ',' IN ',' || visited || ',') > 0;
118 changes: 118 additions & 0 deletions generate_supplier_payment_plans.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
-- Use the memory catalog and default schema
USE memory.default;

-- Ensure the SEXI schema exists
CREATE SCHEMA IF NOT EXISTS SEXI;


-- Define the payment start date (first day of next month)
WITH payment_start AS (
SELECT date_trunc('month', current_date + interval '1' month) AS payment_start_date
),

-- Get the maximum due date from the invoices
max_due_date AS (
SELECT MAX(due_date) AS max_due_date
FROM SEXI.INVOICE
),

-- Generate a series of end-of-month dates from payment start date up to the maximum due date
end_of_months AS (
SELECT date_trunc('month', date) + interval '1' month - interval '1' day AS end_of_month
FROM (
SELECT sequence(
(SELECT payment_start_date FROM payment_start),
(SELECT max_due_date FROM max_due_date),
INTERVAL '1' MONTH
) AS payment_dates
)
CROSS JOIN UNNEST(payment_dates) AS t(date)
),

-- Calculate the number of payments and monthly payment amounts for each invoice
invoice_payments AS (
SELECT
inv.supplier_id,
s.name AS supplier_name,
inv.invoice_amount,
inv.due_date,
date_diff('month', (SELECT payment_start_date FROM payment_start) - INTERVAL '1' DAY, inv.due_date) AS months_till_payment,
inv.invoice_amount / date_diff('month', (SELECT payment_start_date FROM payment_start) - INTERVAL '1' DAY, inv.due_date) AS monthly_payment_raw
FROM SEXI.INVOICE inv
JOIN SEXI.SUPPLIER s ON inv.supplier_id = s.supplier_id
),

-- Adjust monthly payments to handle rounding errors
adjusted_invoice_payments AS (
SELECT
supplier_id,
supplier_name,
invoice_amount,
due_date,
months_till_payment,
ROUND(monthly_payment_raw, 2) AS monthly_payment,
invoice_amount - (ROUND(monthly_payment_raw, 2) * (months_till_payment - 1)) AS last_payment_amount
FROM invoice_payments
),

-- Generate payment schedule for each invoice
invoice_payment_schedule AS (
SELECT
aip.supplier_id,
aip.supplier_name,
aip.invoice_amount,
aip.due_date,
eom.end_of_month AS payment_date,
CASE
WHEN ROW_NUMBER() OVER (PARTITION BY aip.supplier_id, aip.invoice_amount ORDER BY eom.end_of_month) < aip.months_till_payment THEN aip.monthly_payment
ELSE aip.last_payment_amount
END AS payment_amount
FROM adjusted_invoice_payments aip
JOIN end_of_months eom ON eom.end_of_month <= aip.due_date
WHERE eom.end_of_month >= (SELECT payment_start_date FROM payment_start)
),

-- Aggregate payments per supplier per payment date
supplier_payments AS (
SELECT
supplier_id,
supplier_name,
payment_date,
SUM(payment_amount) AS payment_amount
FROM invoice_payment_schedule
GROUP BY supplier_id, supplier_name, payment_date
),

-- Calculate balance outstanding per supplier
balance_outstanding AS (
SELECT
supplier_id,
supplier_name,
SUM(invoice_amount) AS total_balance
FROM adjusted_invoice_payments
GROUP BY supplier_id, supplier_name
),

-- Calculate cumulative payments per supplier to determine balance outstanding after each payment
cumulative_payments AS (
SELECT
sp.supplier_id,
sp.supplier_name,
sp.payment_date,
sp.payment_amount,
bo.total_balance,
SUM(sp.payment_amount) OVER (PARTITION BY sp.supplier_id ORDER BY sp.payment_date) AS cumulative_payment,
bo.total_balance - SUM(sp.payment_amount) OVER (PARTITION BY sp.supplier_id ORDER BY sp.payment_date) AS balance_outstanding
FROM supplier_payments sp
JOIN balance_outstanding bo ON sp.supplier_id = bo.supplier_id
)

-- Final Output
SELECT
supplier_id,
supplier_name,
ROUND(payment_amount, 2) AS payment_amount,
ROUND(balance_outstanding, 2) AS balance_outstanding,
payment_date
FROM cumulative_payments
ORDER BY supplier_id, payment_date;