Belajar Data Analyst - SQL Fundamental
Episode 3 of 28

Belajar Data Analyst - SQL Fundamental

Episode ini membangun fondasi SQL untuk analis: SELECT, WHERE, ORDER BY, JOIN, GROUP BY, HAVING, dan subquery, diuji pada dataset penjualan bisnis di PostgreSQL, lengkap dengan contoh query eksploratif dan kesalahan umum yang sering menjegal pemula

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

Setelah di episode 2 kita menyiapkan kerangka kerja dan data literacy, kini saatnya memegang senjata utama seorang analis: SQL. Hampir semua analisis dimulai dari query — data warehouse, database operasional, sampai BI tool semuanya berbicara bahasa yang sama di balik layar. Kalian tidak bisa menjadi analis yang handal tanpa SQL yang solid.

Episode ini membangun fondasinya: dari SELECT paling sederhana hingga GROUP BY dengan HAVING dan subquery. Kita memakai dataset penjualan e-commerce kecil yang bisa langsung kalian praktikkan di PostgreSQL yang sudah disiapkan di episode 0. Konsep yang kalian kuasai di sini akan menjadi batu loncatan untuk episode 4 (window functions) dan episode 16 (SQL untuk warehouse).

Setup Dataset Latihan

Buat dua tabel sederhana: customers dan orders, lalu isi dengan data contoh.

DDL: tabel customers
CREATE TABLE customers (
    id SERIAL PRIMARY KEY,
    name TEXT NOT NULL,
    city TEXT,
    joined_at DATE
);
DDL: tabel orders
CREATE TABLE orders (
    id SERIAL PRIMARY KEY,
    customer_id INTEGER REFERENCES customers(id),
    product TEXT,
    amount NUMERIC(10,2),
    status TEXT,
    ordered_at TIMESTAMP
);
Seed data contoh
INSERT INTO customers (name, city, joined_at) VALUES
    ('Budi', 'Jakarta', '2024-01-10'),
    ('Sari', 'Bandung', '2024-02-20'),
    ('Andi', 'Jakarta', '2024-03-05'),
    ('Dewi', 'Surabaya', '2024-05-15');
 
INSERT INTO orders (customer_id, product, amount, status, ordered_at) VALUES
    (1, 'Laptop', 15000000, 'completed', '2025-11-01 10:00:00'),
    (2, 'Keyboard', 500000, 'completed', '2025-11-03 11:00:00'),
    (3, 'Mouse', 200000, 'pending', '2025-11-04 09:00:00'),
    (1, 'Monitor', 3000000, 'completed', '2025-11-10 14:00:00'),
    (2, 'Mouse', 200000, 'completed', '2025-12-02 10:30:00'),
    (4, 'Laptop', 16000000, 'completed', '2025-12-15 16:00:00');

Note

Untuk mengikuti episode ini, jalankan skrip di atas satu per satu di psql atau client SQL favorit kalian. Dataset ini sengaja kecil — fokusnya memahami logika query, bukan performa.

SELECT dan WHERE

SELECT menentukan kolom yang diambil, WHERE menyaring baris berdasarkan kondisi.

Pilih kolom dan filter
SELECT name, city
FROM customers
WHERE city = 'Jakarta';

Operator yang sering dipakai analis: =, !=, > , < , >= , <= , IN , BETWEEN , LIKE , dan IS NULL. Contoh kombinasi:

Filter dengan rentang dan status
SELECT product, amount
FROM orders
WHERE amount BETWEEN 200000 AND 5000000
  AND status = 'completed';

Perhatikan NULL: dalam SQL, NULL bukan nol. Kondisi amount = NULL tidak pernah benar — kalian harus memakai amount IS NULL. Ini salah satu sumber bug klasik di SQL.

ORDER BY: Mengurutkan Hasil

Order tertinggi ke terendah
SELECT product, amount
FROM orders
WHERE status = 'completed'
ORDER BY amount DESC;

Tanpa ORDER BY, urutan hasil tidak dijamin — database bebas mengembalikan baris dalam urutan apa pun. Jika urutan penting, selalu nyatakan eksplisit.

JOIN: Menggabungkan Tabel

Data bisnis tersebar di banyak tabel. JOIN menggabungkannya lewat kolom kunci. Jenis yang paling sering dipakai analis:

Inner join: order + nama customer
SELECT o.id, c.name, o.product, o.amount
FROM orders o
JOIN customers c ON c.id = o.customer_id
WHERE o.status = 'completed';
Jenis JOINHasil
INNER JOINHanya baris yang cocok di kedua tabel
LEFT JOINSemua baris kiri, data kanan yang tidak cocok jadi NULL
RIGHT JOINKebalikan LEFT JOIN
FULL JOINSemua baris di kedua sisi

LEFT JOIN adalah senjata utama analis untuk menemukan data yang "hilang" — misalnya customer yang belum pernah order:

LEFT JOIN: customer tanpa order
SELECT c.name, COUNT(o.id) AS total_order
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
GROUP BY c.name;

GROUP BY dan HAVING: Merangkum Data

GROUP BY mengelompokkan baris dan HAVING menyaring hasil agregasi (sedangkan WHERE menyaring baris mentah sebelum agregasi).

Revenue per produk
SELECT product, SUM(amount) AS total_amount, COUNT(*) AS jumlah
FROM orders
WHERE status = 'completed'
GROUP BY product;
HAVING: hanya produk di atas 1 juta
SELECT product, SUM(amount) AS total_amount
FROM orders
WHERE status = 'completed'
GROUP BY product
HAVING SUM(amount) > 1000000;

Urutan logika eksekusi query yang wajib kalian hafal: FROMWHEREGROUP BYHAVINGSELECTORDER BY. Itulah mengapa kalian tidak bisa memakai alias hasil agregasi di dalam WHERE, tetapi bisa di ORDER BY.

Subquery: Query dalam Query

Subquery bisa ditaruh di WHERE, FROM, maupun SELECT. Contoh klasik: membandingkan setiap baris dengan nilai agregat.

Order di atas rata-rata
SELECT id, product, amount
FROM orders
WHERE amount > (SELECT AVG(amount) FROM orders);

Contoh kedua — subquery di FROM sebagai tabel virtual:

Revenue per customer, diurutkan
SELECT name, revenue
FROM (
    SELECT c.name, SUM(o.amount) AS revenue
    FROM customers c
    JOIN orders o ON o.customer_id = c.id
    WHERE o.status = 'completed'
    GROUP BY c.name
) AS summary
ORDER BY revenue DESC;

Kesalahan Umum

  • Lupa WHERE pada COUNT. COUNT(*) menghitung semua baris; untuk menghitung subset, filter dulu di WHERE.
  • Kolom non-agregat tanpa GROUP BY. Memilih name bersama SUM(amount) tanpa GROUP BY name akan error — atau lebih buruk, hasil tak menentu di database lain.
  • WHERE dipakai untuk filter agregasi. Ingat urutan eksekusi: agregasi hanya bisa difilter dengan HAVING.
  • **Perbandingan NULL dengan =. Selalu pakai IS NULL / IS NOT NULL.
  • Join tanpa kondisi. JOIN tanpa ON menghasilkan cartesian product yang diam-diam menggandakan baris.

Penutup

Inti yang harus dibawa pulang:

  • SELECT + WHERE adalah gerbang utama mengambil dan menyaring data.
  • JOIN menggabungkan tabel lewat kunci; LEFT JOIN sangat berguna untuk menemukan data yang hilang.
  • GROUP BY + HAVING untuk agregasi; hafalkan urutan eksekusi logis query.
  • Subquery memberi kemampuan query bertingkat untuk perbandingan agregat.
  • NULL adalah jebakan: selalu bandingkan dengan IS NULL.

Di episode 4 selanjutnya kita akan menaikkan level SQL kalian: window functions (ROW_NUMBER, RANK, LAG/LEAD), CTE, dan optimasi query — lengkap dengan analisis cohort & retention yang menjadi skill wajib analis. Pastikan kalian sudah nyaman dengan episode 3, karena semua akan kalian pakai di sana!