SQL untuk Data Engineering — Data Engineering

SQL Advanced untuk Data Engineering Sebagai data engineer, SQL bukan hanya SELECT-WHERE-JOIN. Kamu butuh window functions, CTEs, dan analytical queries untuk tr

SQL Advanced untuk Data Engineering

Sebagai data engineer, SQL bukan hanya SELECT-WHERE-JOIN. Kamu butuh window functions, CTEs, dan analytical queries untuk transformasi data yang kompleks.

CTE (Common Table Expressions)

CTE membuat query lebih readable dengan memecah logic menjadi langkah-langkah.

-- Tanpa CTE: nested subquery susah dibaca
SELECT * FROM (
    SELECT user_id, SUM(amount) as total
    FROM orders GROUP BY user_id
) sub WHERE total > 1000000;

-- Dengan CTE: jelas dan bertahap
WITH user_totals AS (
    SELECT user_id, SUM(amount) AS total_spend
    FROM orders
    GROUP BY user_id
),
high_value AS (
    SELECT * FROM user_totals
    WHERE total_spend > 1000000
)
SELECT u.name, h.total_spend
FROM high_value h
JOIN users u ON u.id = h.user_id
ORDER BY h.total_spend DESC;

Window Functions

Menghitung agregasi tanpa menghilangkan baris — sangat powerful untuk analitik.

-- ROW_NUMBER: ranking per group
SELECT
    user_id,
    order_date,
    amount,
    ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY order_date) AS order_sequence
FROM orders;

-- Running total (kumulatif)
SELECT
    order_date,
    amount,
    SUM(amount) OVER (ORDER BY order_date) AS running_total
FROM orders;

-- Moving average (rata-rata 7 hari terakhir)
SELECT
    date,
    daily_revenue,
    AVG(daily_revenue) OVER (
        ORDER BY date
        ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
    ) AS moving_avg_7d
FROM daily_metrics;

-- LAG / LEAD: akses baris sebelum/sesudah
SELECT
    date,
    daily_revenue,
    LAG(daily_revenue, 1) OVER (ORDER BY date) AS prev_day,
    daily_revenue - LAG(daily_revenue, 1) OVER (ORDER BY date) AS day_over_day_change
FROM daily_metrics;

Analytical Patterns

-- Cohort analysis: kapan user pertama kali order?
WITH first_order AS (
    SELECT user_id, MIN(DATE_TRUNC('month', order_date)) AS cohort_month
    FROM orders GROUP BY user_id
)
SELECT
    f.cohort_month,
    DATE_TRUNC('month', o.order_date) AS activity_month,
    COUNT(DISTINCT o.user_id) AS active_users
FROM orders o
JOIN first_order f ON f.user_id = o.user_id
GROUP BY 1, 2
ORDER BY 1, 2;

-- NTILE: bagi data jadi bucket (quartile, decile)
SELECT
    user_id,
    total_spend,
    NTILE(4) OVER (ORDER BY total_spend) AS spend_quartile
FROM user_summary;

Yang akan kamu pelajari