| | |
| | |
| |
|
| | |
| | |
| | |
| |
|
| | CREATE TABLE raw.customers ( |
| | customer_id INTEGER PRIMARY KEY, |
| | email VARCHAR(255) NOT NULL, |
| | first_name VARCHAR(100), |
| | last_name VARCHAR(100), |
| | created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, |
| | country VARCHAR(50), |
| | segment VARCHAR(50) |
| | ); |
| |
|
| | CREATE TABLE raw.orders ( |
| | order_id INTEGER PRIMARY KEY, |
| | customer_id INTEGER REFERENCES raw.customers(customer_id), |
| | order_date DATE NOT NULL, |
| | total_amount DECIMAL(10,2), |
| | currency VARCHAR(3) DEFAULT 'USD', |
| | status VARCHAR(20), |
| | shipping_address_id INTEGER |
| | ); |
| |
|
| | CREATE TABLE raw.products ( |
| | product_id INTEGER PRIMARY KEY, |
| | product_name VARCHAR(255) NOT NULL, |
| | category VARCHAR(100), |
| | subcategory VARCHAR(100), |
| | brand VARCHAR(100), |
| | price DECIMAL(10,2), |
| | cost DECIMAL(10,2) |
| | ); |
| |
|
| | CREATE TABLE raw.order_items ( |
| | order_item_id INTEGER PRIMARY KEY, |
| | order_id INTEGER REFERENCES raw.orders(order_id), |
| | product_id INTEGER REFERENCES raw.products(product_id), |
| | quantity INTEGER NOT NULL, |
| | unit_price DECIMAL(10,2), |
| | discount_percent DECIMAL(5,2) DEFAULT 0 |
| | ); |
| |
|
| | |
| | |
| | |
| |
|
| | CREATE VIEW staging.stg_customers AS |
| | SELECT |
| | customer_id, |
| | LOWER(TRIM(email)) as email, |
| | INITCAP(first_name) as first_name, |
| | INITCAP(last_name) as last_name, |
| | DATE(created_at) as signup_date, |
| | UPPER(country) as country, |
| | COALESCE(segment, 'Unknown') as segment |
| | FROM raw.customers |
| | WHERE email IS NOT NULL; |
| | |
| |
|
| | CREATE VIEW staging.stg_orders AS |
| | SELECT |
| | order_id, |
| | customer_id, |
| | order_date, |
| | total_amount, |
| | currency, |
| | CASE |
| | WHEN status IN ('completed', 'shipped', 'delivered') THEN 'Fulfilled' |
| | WHEN status IN ('pending', 'processing') THEN 'In Progress' |
| | ELSE 'Other' |
| | END as order_status |
| | FROM raw.orders |
| | WHERE order_date >= '2024-01-01'; |
| | |
| |
|
| | CREATE VIEW staging.stg_products AS |
| | SELECT |
| | product_id, |
| | product_name, |
| | category, |
| | subcategory, |
| | brand, |
| | price, |
| | cost, |
| | (price - cost) / NULLIF(price, 0) * 100 as margin_percent |
| | FROM raw.products |
| | WHERE price > 0; |
| | |
| |
|
| | CREATE VIEW staging.stg_order_items AS |
| | SELECT |
| | order_item_id, |
| | order_id, |
| | product_id, |
| | quantity, |
| | unit_price, |
| | discount_percent, |
| | quantity * unit_price * (1 - discount_percent/100) as line_total |
| | FROM raw.order_items; |
| | |
| |
|
| | |
| | |
| | |
| |
|
| | CREATE TABLE intermediate.int_customer_orders AS |
| | SELECT |
| | c.customer_id, |
| | c.email, |
| | c.first_name, |
| | c.last_name, |
| | c.signup_date, |
| | c.country, |
| | c.segment, |
| | COUNT(DISTINCT o.order_id) as total_orders, |
| | SUM(o.total_amount) as total_spent, |
| | MIN(o.order_date) as first_order_date, |
| | MAX(o.order_date) as last_order_date, |
| | AVG(o.total_amount) as avg_order_value |
| | FROM staging.stg_customers c |
| | LEFT JOIN staging.stg_orders o ON c.customer_id = o.customer_id |
| | GROUP BY c.customer_id, c.email, c.first_name, c.last_name, |
| | c.signup_date, c.country, c.segment; |
| | |
| |
|
| | CREATE TABLE intermediate.int_order_details AS |
| | SELECT |
| | o.order_id, |
| | o.customer_id, |
| | o.order_date, |
| | o.order_status, |
| | oi.product_id, |
| | p.product_name, |
| | p.category, |
| | p.brand, |
| | oi.quantity, |
| | oi.unit_price, |
| | oi.line_total, |
| | p.margin_percent |
| | FROM staging.stg_orders o |
| | JOIN staging.stg_order_items oi ON o.order_id = oi.order_id |
| | JOIN staging.stg_products p ON oi.product_id = p.product_id; |
| | |
| |
|
| | |
| | |
| | |
| |
|
| | CREATE TABLE marts.dim_customers AS |
| | SELECT |
| | customer_id, |
| | email, |
| | first_name || ' ' || last_name as full_name, |
| | signup_date, |
| | country, |
| | segment, |
| | total_orders, |
| | total_spent, |
| | first_order_date, |
| | last_order_date, |
| | avg_order_value, |
| | CASE |
| | WHEN total_spent > 10000 THEN 'Platinum' |
| | WHEN total_spent > 5000 THEN 'Gold' |
| | WHEN total_spent > 1000 THEN 'Silver' |
| | ELSE 'Bronze' |
| | END as customer_tier, |
| | DATEDIFF(day, signup_date, first_order_date) as days_to_first_order |
| | FROM intermediate.int_customer_orders; |
| | |
| |
|
| | CREATE TABLE marts.dim_products AS |
| | SELECT |
| | product_id, |
| | product_name, |
| | category, |
| | subcategory, |
| | brand, |
| | price, |
| | cost, |
| | margin_percent, |
| | CASE |
| | WHEN margin_percent > 50 THEN 'High Margin' |
| | WHEN margin_percent > 25 THEN 'Medium Margin' |
| | ELSE 'Low Margin' |
| | END as margin_tier |
| | FROM staging.stg_products; |
| | |
| |
|
| | CREATE TABLE marts.fct_orders AS |
| | SELECT |
| | od.order_id, |
| | od.customer_id, |
| | od.product_id, |
| | od.order_date, |
| | od.order_status, |
| | od.quantity, |
| | od.unit_price, |
| | od.line_total, |
| | od.margin_percent, |
| | dc.customer_tier, |
| | dp.margin_tier, |
| | dp.category as product_category |
| | FROM intermediate.int_order_details od |
| | JOIN marts.dim_customers dc ON od.customer_id = dc.customer_id |
| | JOIN marts.dim_products dp ON od.product_id = dp.product_id; |
| | |
| |
|
| | |
| | |
| | |
| |
|
| | CREATE VIEW reporting.rpt_daily_sales AS |
| | SELECT |
| | order_date, |
| | product_category, |
| | COUNT(DISTINCT order_id) as num_orders, |
| | SUM(quantity) as units_sold, |
| | SUM(line_total) as gross_revenue, |
| | AVG(line_total) as avg_order_value |
| | FROM marts.fct_orders |
| | GROUP BY order_date, product_category; |
| | |
| |
|
| | CREATE VIEW reporting.rpt_customer_ltv AS |
| | SELECT |
| | customer_id, |
| | full_name, |
| | customer_tier, |
| | country, |
| | total_orders, |
| | total_spent as lifetime_value, |
| | avg_order_value, |
| | days_to_first_order, |
| | DATEDIFF(day, first_order_date, last_order_date) as customer_lifespan_days, |
| | total_spent / NULLIF(DATEDIFF(month, first_order_date, last_order_date), 0) as monthly_value |
| | FROM marts.dim_customers |
| | WHERE total_orders > 0; |
| | |
| |
|
| | CREATE VIEW reporting.rpt_product_performance AS |
| | SELECT |
| | dp.product_id, |
| | dp.product_name, |
| | dp.category, |
| | dp.brand, |
| | dp.margin_tier, |
| | COUNT(DISTINCT fo.order_id) as times_ordered, |
| | SUM(fo.quantity) as total_units_sold, |
| | SUM(fo.line_total) as total_revenue, |
| | AVG(fo.margin_percent) as avg_margin |
| | FROM marts.dim_products dp |
| | LEFT JOIN marts.fct_orders fo ON dp.product_id = fo.product_id |
| | GROUP BY dp.product_id, dp.product_name, dp.category, dp.brand, dp.margin_tier; |
| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|