| |
| |
|
|
| |
| |
| |
|
|
| 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; |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|