50 Pertanyaan Interview SQL untuk Data Analyst (Dengan Jawaban)
TL;DR
50 soal interview SQL dibagi 3 level: 15 Basic (SELECT, WHERE, ORDER BY), 20 Intermediate (JOIN, GROUP BY, Subquery), 15 Advanced (Window Functions, CTE, Optimization). Semua pakai konteks perusahaan tech Indonesia.
Kenapa Interview SQL Itu Penting?
Mau apply jadi Data Analyst, Data Scientist, atau Data Engineer di perusahaan tech Indonesia? SQL pasti jadi salah satu skill yang di-test. Hampir semua perusahaan kayak Gojek, Tokopedia, Shopee, Traveloka, dan startup lainnya punya technical interview SQL.
Aku udah compile 50 pertanyaan yang sering muncul di interview, dari pengalaman sendiri dan temen-temen yang udah kerja di berbagai perusahaan. Semua contoh pakai konteks bisnis Indonesia biar lebih relatable.
Gimana Cara Pakai Artikel Ini?
- Coba jawab dulu sebelum liat solusi
- Pahami logikanya, bukan cuma hafal query
- Praktek di SQL editor (DB Fiddle, NgulikSQL, atau local database)
- Ulangi yang salah sampai bener-bener paham
Dataset yang Dipakai
Untuk semua soal, kita pakai dataset e-commerce dengan 4 tabel:
Tabel: users
| user_id | nama | kota | tanggal_daftar |
|---|---|---|---|
| 1 | Budi Santoso | Jakarta | 2024-01-15 |
| 2 | Siti Rahayu | Bandung | 2024-02-20 |
| 3 | Andi Wijaya | Surabaya | 2024-01-10 |
Tabel: orders
| order_id | user_id | total_amount | order_date | status |
|---|---|---|---|---|
| 101 | 1 | 150000 | 2024-03-01 | completed |
| 102 | 1 | 250000 | 2024-03-15 | completed |
| 103 | 2 | 100000 | 2024-03-10 | cancelled |
Tabel: products
| product_id | nama_produk | kategori | harga |
|---|---|---|---|
| 1 | Kaos Polos | Fashion | 75000 |
| 2 | Sepatu Sneakers | Fashion | 450000 |
| 3 | Headphone | Elektronik | 250000 |
Tabel: order_items
| id | order_id | product_id | quantity | price |
|---|---|---|---|---|
| 1 | 101 | 1 | 2 | 75000 |
| 2 | 101 | 3 | 1 | 250000 |
| 3 | 102 | 2 | 1 | 450000 |
Level 1: Basic (15 Pertanyaan)
Soal 1: SELECT Semua Data
Pertanyaan: Tampilkan semua data dari tabel users.
Jawaban
SELECT * FROM users;
**Penjelasan:** `SELECT *` artinya ambil semua kolom. Tapi di production, lebih baik sebutin kolom yang dibutuhkan aja.
Soal 2: SELECT Kolom Tertentu
Pertanyaan: Tampilkan nama dan kota dari semua users.
Jawaban
SELECT nama, kota FROM users;
Soal 3: WHERE dengan Kondisi Equals
Pertanyaan: Tampilkan semua users yang tinggal di Jakarta.
Jawaban
SELECT * FROM users WHERE kota = 'Jakarta';
Soal 4: WHERE dengan Multiple Conditions
Pertanyaan: Tampilkan orders yang statusnya 'completed' DAN total_amount lebih dari 200000.
Jawaban
SELECT * FROM orders
WHERE status = 'completed' AND total_amount > 200000;
Soal 5: ORDER BY
Pertanyaan: Tampilkan semua products, urutkan dari harga termahal.
Jawaban
SELECT * FROM products ORDER BY harga DESC;
**Penjelasan:** `DESC` = descending (besar ke kecil). Default-nya `ASC` (kecil ke besar).
Soal 6: LIMIT
Pertanyaan: Tampilkan 5 orders terbaru.
Jawaban
SELECT * FROM orders ORDER BY order_date DESC LIMIT 5;
Soal 7: DISTINCT
Pertanyaan: Tampilkan daftar kota unik dari tabel users.
Jawaban
SELECT DISTINCT kota FROM users;
Soal 8: IN Operator
Pertanyaan: Tampilkan users yang tinggal di Jakarta atau Bandung.
Jawaban
SELECT * FROM users WHERE kota IN ('Jakarta', 'Bandung');
**Alternatif:**
SELECT * FROM users WHERE kota = 'Jakarta' OR kota = 'Bandung';
Soal 9: BETWEEN
Pertanyaan: Tampilkan products dengan harga antara 100000 dan 300000.
Jawaban
SELECT * FROM products WHERE harga BETWEEN 100000 AND 300000;
**Note:** BETWEEN itu inclusive (termasuk batas atas dan bawah).
Soal 10: LIKE Pattern Matching
Pertanyaan: Tampilkan users yang namanya diawali huruf 'S'.
Jawaban
SELECT * FROM users WHERE nama LIKE 'S%';
**Penjelasan:** `%` artinya karakter apapun, berapapun jumlahnya.
Soal 11: NULL Handling
Pertanyaan: Tampilkan orders yang statusnya NULL.
Jawaban
SELECT * FROM orders WHERE status IS NULL;
**Jebakan:** `WHERE status = NULL` ga akan work. Harus pakai `IS NULL`.
Soal 12: COUNT
Pertanyaan: Hitung jumlah total users.
Jawaban
SELECT COUNT(*) AS total_users FROM users;
Soal 13: SUM
Pertanyaan: Hitung total revenue dari semua orders yang completed.
Jawaban
SELECT SUM(total_amount) AS total_revenue
FROM orders
WHERE status = 'completed';
Soal 14: AVG
Pertanyaan: Hitung rata-rata harga produk.
Jawaban
SELECT AVG(harga) AS rata_rata_harga FROM products;
Soal 15: Alias
Pertanyaan: Tampilkan nama user dan kota, dengan nama kolom "Nama Lengkap" dan "Domisili".
Jawaban
SELECT
nama AS "Nama Lengkap",
kota AS "Domisili"
FROM users;
Level 2: Intermediate (20 Pertanyaan)
Soal 16: INNER JOIN
Pertanyaan: Tampilkan nama user beserta order_id dan total_amount dari orders mereka.
Jawaban
SELECT u.nama, o.order_id, o.total_amount
FROM users u
INNER JOIN orders o ON u.user_id = o.user_id;
Soal 17: LEFT JOIN
Pertanyaan: Tampilkan semua users beserta orders mereka (termasuk user yang belum pernah order).
Jawaban
SELECT u.nama, o.order_id, o.total_amount
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id;
Soal 18: JOIN dengan Filter
Pertanyaan: Tampilkan nama user dan total order mereka, hanya untuk orders yang completed.
Jawaban
SELECT u.nama, o.order_id, o.total_amount
FROM users u
INNER JOIN orders o ON u.user_id = o.user_id
WHERE o.status = 'completed';
Soal 19: Multiple JOINs
Pertanyaan: Tampilkan order_id, nama user, nama produk, dan quantity untuk setiap item yang diorder.
Jawaban
SELECT
o.order_id,
u.nama AS nama_user,
p.nama_produk,
oi.quantity
FROM orders o
INNER JOIN users u ON o.user_id = u.user_id
INNER JOIN order_items oi ON o.order_id = oi.order_id
INNER JOIN products p ON oi.product_id = p.product_id;
Soal 20: GROUP BY Basic
Pertanyaan: Hitung jumlah orders per user.
Jawaban
SELECT user_id, COUNT(*) AS jumlah_order
FROM orders
GROUP BY user_id;
Soal 21: GROUP BY dengan JOIN
Pertanyaan: Tampilkan nama user dan total spending mereka.
Jawaban
SELECT u.nama, SUM(o.total_amount) AS total_spending
FROM users u
INNER JOIN orders o ON u.user_id = o.user_id
WHERE o.status = 'completed'
GROUP BY u.user_id, u.nama;
Soal 22: HAVING
Pertanyaan: Tampilkan user yang punya total spending lebih dari 200000.
Jawaban
SELECT u.nama, SUM(o.total_amount) AS total_spending
FROM users u
INNER JOIN orders o ON u.user_id = o.user_id
WHERE o.status = 'completed'
GROUP BY u.user_id, u.nama
HAVING SUM(o.total_amount) > 200000;
**Penjelasan:** `WHERE` filter sebelum GROUP BY, `HAVING` filter setelah GROUP BY.
Soal 23: Subquery di WHERE
Pertanyaan: Tampilkan users yang pernah order dengan total_amount di atas rata-rata.
Jawaban
SELECT DISTINCT u.nama
FROM users u
INNER JOIN orders o ON u.user_id = o.user_id
WHERE o.total_amount > (SELECT AVG(total_amount) FROM orders);
Soal 24: Subquery di FROM
Pertanyaan: Tampilkan rata-rata jumlah order per user.
Jawaban
SELECT AVG(order_count) AS avg_orders_per_user
FROM (
SELECT user_id, COUNT(*) AS order_count
FROM orders
GROUP BY user_id
) AS user_orders;
Soal 25: CASE WHEN
Pertanyaan: Kategorikan users berdasarkan total spending: 'Bronze' (<100k), 'Silver' (100k-300k), 'Gold' (>300k).
Jawaban
SELECT
u.nama,
SUM(o.total_amount) AS total_spending,
CASE
WHEN SUM(o.total_amount) < 100000 THEN 'Bronze'
WHEN SUM(o.total_amount) BETWEEN 100000 AND 300000 THEN 'Silver'
ELSE 'Gold'
END AS tier
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id AND o.status = 'completed'
GROUP BY u.user_id, u.nama;
Soal 26: Date Functions
Pertanyaan: Tampilkan orders yang terjadi di bulan Maret 2024.
Jawaban
-- PostgreSQL
SELECT * FROM orders
WHERE EXTRACT(MONTH FROM order_date) = 3
AND EXTRACT(YEAR FROM order_date) = 2024;
-- MySQL
SELECT * FROM orders
WHERE MONTH(order_date) = 3 AND YEAR(order_date) = 2024;
-- Alternatif universal
SELECT * FROM orders
WHERE order_date >= '2024-03-01' AND order_date < '2024-04-01';
Soal 27: COALESCE
Pertanyaan: Tampilkan nama user dan total spending, ganti NULL dengan 0.
Jawaban
SELECT
u.nama,
COALESCE(SUM(o.total_amount), 0) AS total_spending
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id AND o.status = 'completed'
GROUP BY u.user_id, u.nama;
Soal 28: Self JOIN
Pertanyaan: Cari pasangan produk yang harganya sama.
Jawaban
SELECT
p1.nama_produk AS produk_1,
p2.nama_produk AS produk_2,
p1.harga
FROM products p1
INNER JOIN products p2 ON p1.harga = p2.harga
WHERE p1.product_id < p2.product_id;
**Penjelasan:** `p1.product_id < p2.product_id` biar ga ada duplikat pasangan.
Soal 29: UNION
Pertanyaan: Gabungkan daftar nama user dan nama produk dalam satu kolom.
Jawaban
SELECT nama AS nama, 'user' AS tipe FROM users
UNION
SELECT nama_produk AS nama, 'produk' AS tipe FROM products;
**Penjelasan:** `UNION` menghilangkan duplikat. Pakai `UNION ALL` kalau mau keep duplikat.
Soal 30: EXISTS
Pertanyaan: Tampilkan users yang pernah melakukan order.
Jawaban
SELECT * FROM users u
WHERE EXISTS (
SELECT 1 FROM orders o WHERE o.user_id = u.user_id
);
Soal 31: NOT IN
Pertanyaan: Tampilkan users yang BELUM pernah order.
Jawaban
SELECT * FROM users
WHERE user_id NOT IN (SELECT DISTINCT user_id FROM orders);
**Alternatif dengan LEFT JOIN:**
SELECT u.* FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id
WHERE o.order_id IS NULL;
Soal 32: String Functions
Pertanyaan: Tampilkan nama user dalam huruf kapital dan 3 huruf pertama kotanya.
Jawaban
SELECT
UPPER(nama) AS nama_kapital,
LEFT(kota, 3) AS kode_kota
FROM users;
Soal 33: Hitung Selisih Tanggal
Pertanyaan: Hitung berapa hari sejak user mendaftar sampai order pertama mereka.
Jawaban
SELECT
u.nama,
u.tanggal_daftar,
MIN(o.order_date) AS first_order,
MIN(o.order_date) - u.tanggal_daftar AS days_to_first_order
FROM users u
INNER JOIN orders o ON u.user_id = o.user_id
GROUP BY u.user_id, u.nama, u.tanggal_daftar;
Soal 34: Persentase
Pertanyaan: Hitung persentase orders yang completed vs total orders.
Jawaban
SELECT
ROUND(
COUNT(CASE WHEN status = 'completed' THEN 1 END) * 100.0 / COUNT(*),
2
) AS completion_rate
FROM orders;
Soal 35: Top N per Group
Pertanyaan: Tampilkan produk termahal di setiap kategori.
Jawaban
SELECT p1.*
FROM products p1
WHERE p1.harga = (
SELECT MAX(p2.harga)
FROM products p2
WHERE p2.kategori = p1.kategori
);
Level 3: Advanced (15 Pertanyaan)
Soal 36: Window Function - ROW_NUMBER
Pertanyaan: Beri ranking users berdasarkan total spending mereka.
Jawaban
SELECT
u.nama,
SUM(o.total_amount) AS total_spending,
ROW_NUMBER() OVER (ORDER BY SUM(o.total_amount) DESC) AS ranking
FROM users u
INNER JOIN orders o ON u.user_id = o.user_id
WHERE o.status = 'completed'
GROUP BY u.user_id, u.nama;
Soal 37: RANK vs DENSE_RANK
Pertanyaan: Beri ranking produk berdasarkan harga. Jelaskan perbedaan RANK dan DENSE_RANK.
Jawaban
SELECT
nama_produk,
harga,
RANK() OVER (ORDER BY harga DESC) AS rank_biasa,
DENSE_RANK() OVER (ORDER BY harga DESC) AS dense_rank
FROM products;
**Penjelasan:**
- RANK: Kalau ada tie, ranking selanjutnya loncat. Misal: 1, 2, 2, 4
- DENSE_RANK: Kalau ada tie, ranking selanjutnya tetap berurutan. Misal: 1, 2, 2, 3
Soal 38: LAG dan LEAD
Pertanyaan: Untuk setiap order, tampilkan total_amount order sebelumnya dari user yang sama.
Jawaban
SELECT
user_id,
order_id,
order_date,
total_amount,
LAG(total_amount) OVER (PARTITION BY user_id ORDER BY order_date) AS prev_order_amount
FROM orders;
Soal 39: Running Total
Pertanyaan: Hitung running total revenue per tanggal.
Jawaban
SELECT
order_date,
total_amount,
SUM(total_amount) OVER (ORDER BY order_date) AS running_total
FROM orders
WHERE status = 'completed';
Soal 40: Moving Average
Pertanyaan: Hitung 3-day moving average dari daily revenue.
Jawaban
WITH daily_revenue AS (
SELECT
order_date,
SUM(total_amount) AS revenue
FROM orders
WHERE status = 'completed'
GROUP BY order_date
)
SELECT
order_date,
revenue,
AVG(revenue) OVER (
ORDER BY order_date
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
) AS moving_avg_3day
FROM daily_revenue;
Soal 41: CTE (Common Table Expression)
Pertanyaan: Gunakan CTE untuk mencari users dengan spending di atas rata-rata.
Jawaban
WITH user_spending AS (
SELECT
u.user_id,
u.nama,
SUM(o.total_amount) AS total_spending
FROM users u
INNER JOIN orders o ON u.user_id = o.user_id
WHERE o.status = 'completed'
GROUP BY u.user_id, u.nama
),
avg_spending AS (
SELECT AVG(total_spending) AS avg_spend FROM user_spending
)
SELECT us.*
FROM user_spending us, avg_spending
WHERE us.total_spending > avg_spending.avg_spend;
Soal 42: Recursive CTE
Pertanyaan: Generate deret angka 1 sampai 10 menggunakan Recursive CTE.
Jawaban
WITH RECURSIVE numbers AS (
SELECT 1 AS n
UNION ALL
SELECT n + 1 FROM numbers WHERE n < 10
)
SELECT * FROM numbers;
Soal 43: Cohort Analysis - Month-over-Month Retention
Pertanyaan: Hitung retention rate user berdasarkan bulan registrasi.
Jawaban
WITH user_cohort AS (
SELECT
user_id,
DATE_TRUNC('month', tanggal_daftar) AS cohort_month
FROM users
),
user_activity AS (
SELECT
o.user_id,
DATE_TRUNC('month', o.order_date) AS activity_month
FROM orders o
)
SELECT
uc.cohort_month,
ua.activity_month,
COUNT(DISTINCT uc.user_id) AS users
FROM user_cohort uc
LEFT JOIN user_activity ua ON uc.user_id = ua.user_id
GROUP BY uc.cohort_month, ua.activity_month
ORDER BY uc.cohort_month, ua.activity_month;
Soal 44: Pivot Table
Pertanyaan: Buat pivot table: baris = kategori, kolom = bulan, value = total penjualan.
Jawaban
SELECT
p.kategori,
SUM(CASE WHEN EXTRACT(MONTH FROM o.order_date) = 1 THEN oi.quantity * oi.price ELSE 0 END) AS jan,
SUM(CASE WHEN EXTRACT(MONTH FROM o.order_date) = 2 THEN oi.quantity * oi.price ELSE 0 END) AS feb,
SUM(CASE WHEN EXTRACT(MONTH FROM o.order_date) = 3 THEN oi.quantity * oi.price ELSE 0 END) AS mar
FROM products p
LEFT JOIN order_items oi ON p.product_id = oi.product_id
LEFT JOIN orders o ON oi.order_id = o.order_id
GROUP BY p.kategori;
Soal 45: Funnel Analysis
Pertanyaan: Hitung conversion rate dari user daftar → order pertama → order kedua.
Jawaban
WITH user_orders AS (
SELECT
user_id,
COUNT(*) AS order_count
FROM orders
GROUP BY user_id
)
SELECT
COUNT(DISTINCT u.user_id) AS total_users,
COUNT(DISTINCT uo.user_id) AS users_with_order,
COUNT(DISTINCT CASE WHEN uo.order_count >= 2 THEN uo.user_id END) AS users_with_2_orders,
ROUND(COUNT(DISTINCT uo.user_id) * 100.0 / COUNT(DISTINCT u.user_id), 2) AS conv_to_first_order,
ROUND(COUNT(DISTINCT CASE WHEN uo.order_count >= 2 THEN uo.user_id END) * 100.0 / COUNT(DISTINCT uo.user_id), 2) AS conv_to_second_order
FROM users u
LEFT JOIN user_orders uo ON u.user_id = uo.user_id;
Soal 46: Duplicate Detection
Pertanyaan: Cari user yang punya email duplikat (asumsikan ada kolom email).
Jawaban
SELECT email, COUNT(*) AS count
FROM users
GROUP BY email
HAVING COUNT(*) > 1;
**Untuk lihat detail row-nya:**
SELECT * FROM users
WHERE email IN (
SELECT email FROM users GROUP BY email HAVING COUNT(*) > 1
);
Soal 47: Gap and Islands
Pertanyaan: Identifikasi periode consecutive days dimana ada order.
Jawaban
WITH dated_orders AS (
SELECT DISTINCT order_date,
order_date - ROW_NUMBER() OVER (ORDER BY order_date) * INTERVAL '1 day' AS grp
FROM orders
)
SELECT
MIN(order_date) AS start_date,
MAX(order_date) AS end_date,
COUNT(*) AS consecutive_days
FROM dated_orders
GROUP BY grp
ORDER BY start_date;
Soal 48: Query Optimization
Pertanyaan: Query ini lambat. Gimana cara optimize-nya?
SELECT * FROM orders
WHERE YEAR(order_date) = 2024 AND user_id IN (SELECT user_id FROM users WHERE kota = 'Jakarta');
Jawaban
-- Optimized version
SELECT o.*
FROM orders o
INNER JOIN users u ON o.user_id = u.user_id
WHERE o.order_date >= '2024-01-01'
AND o.order_date < '2025-01-01'
AND u.kota = 'Jakarta';
**Tips optimasi:**
1. Hindari function di kolom (YEAR(order_date)) karena ga bisa pakai index
2. Ganti subquery dengan JOIN kalau memungkinkan
3. Pastikan ada index di kolom yang sering di-filter
Soal 49: EXPLAIN Query
Pertanyaan: Apa yang dilihat dari EXPLAIN dan gimana interpretasinya?
Jawaban
EXPLAIN SELECT * FROM orders WHERE user_id = 1;
**Yang perlu diperhatikan:**
- **Seq Scan** = Full table scan, lambat untuk tabel besar
- **Index Scan** = Pakai index, lebih cepat
- **Rows** = Estimasi jumlah baris yang di-scan
- **Cost** = Estimasi biaya query (lower = better)
**Red flags:**
- Seq Scan di tabel besar
- Cost yang tinggi
- Rows yang jauh lebih besar dari yang di-return
Soal 50: Conditional Aggregation Complex
Pertanyaan: Untuk setiap user, hitung: total orders, completed orders, cancelled orders, completion rate, dan average order value.
Jawaban
SELECT
u.nama,
COUNT(o.order_id) AS total_orders,
COUNT(CASE WHEN o.status = 'completed' THEN 1 END) AS completed_orders,
COUNT(CASE WHEN o.status = 'cancelled' THEN 1 END) AS cancelled_orders,
ROUND(
COUNT(CASE WHEN o.status = 'completed' THEN 1 END) * 100.0 / NULLIF(COUNT(o.order_id), 0),
2
) AS completion_rate,
ROUND(AVG(CASE WHEN o.status = 'completed' THEN o.total_amount END), 0) AS avg_order_value
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id
GROUP BY u.user_id, u.nama
ORDER BY total_orders DESC;
Tips Menghadapi Interview SQL
Sebelum Interview
- Latihan rutin - Minimal 30 menit sehari di platform kayak NgulikSQL, DataLemur, atau LeetCode
- Pahami fundamentals - JOIN, GROUP BY, Window Functions, CTE
- Pelajari database yang dipake - PostgreSQL, MySQL, atau BigQuery punya syntax yang beda-beda
Saat Interview
- Clarify requirements - Tanya kalau ada yang ga jelas
- Think out loud - Interviewer mau liat proses thinking kamu
- Start simple - Bikin query basic dulu, baru optimize
- Test with edge cases - NULL values, empty results, duplicates
Red Flags yang Harus Dihindari
- SELECT * - Sebutin kolom yang dibutuhkan aja
- Ga pakai alias - Query jadi susah dibaca
- Cartesian product - Lupa ON clause di JOIN
- Ga handle NULL - Pakai COALESCE atau IS NULL
Key Takeaways
-
Basic (Level 1) fokus ke SELECT, WHERE, ORDER BY, dan aggregate functions. Ini fondasi yang wajib dikuasai.
-
Intermediate (Level 2) fokus ke JOIN, GROUP BY, HAVING, dan subquery. Di sini mulai bisa analisis data yang lebih kompleks.
-
Advanced (Level 3) fokus ke Window Functions, CTE, dan optimization. Ini yang membedakan junior dan senior.
-
Praktek > Teori - Ga cukup baca doang, harus coba sendiri.
-
Pahami bisnis - Query yang bagus adalah query yang menjawab pertanyaan bisnis dengan efisien.
Selanjutnya
Kalau udah paham 50 soal ini, next step-nya:
- Window Functions SQL: ROW_NUMBER, RANK, DENSE_RANK
- Common Table Expression (CTE) di SQL
- Cohort Analysis dengan SQL
Latihan Lebih Lanjut
Mau latihan lebih? Cek NgulikSQL buat soal-soal dengan konteks Indonesia. Atau join komunitas Discord kita buat diskusi dan tanya jawab.
Good luck buat interview-nya! Kamu pasti bisa.
Happy querying!
Artikel Terkait
Fungsi GROUP BY dan HAVING di SQL: Panduan Lengkap
Pelajari cara pakai GROUP BY dan HAVING untuk agregasi data di SQL dengan contoh dataset penjualan UMKM Indonesia
Cara Menggunakan Subquery di SQL (Dengan 10 Contoh Praktis)
Pelajari cara pakai subquery di SQL dengan 10 contoh praktis menggunakan dataset e-commerce Indonesia
Perbedaan INNER JOIN, LEFT JOIN, RIGHT JOIN, dan FULL JOIN di SQL
Belajar perbedaan jenis-jenis JOIN di SQL dengan contoh praktis dan visualisasi. Panduan lengkap INNER, LEFT, RIGHT, dan FULL JOIN untuk pemula.