30-DAY INTENSIVE LEARNING PATH

Belajar SQL
dari Nol Sampai Expert

Panduan lengkap 30 hari β€” dari tidak tahu apa-apa tentang SQL hingga mampu menulis query analisis bisnis tingkat lanjut

πŸ“…
30 Hari
⏱️
2-3 Jam/Hari
πŸ› οΈ
DBeaver + SQLite
πŸ“Š
4 Level
πŸ‹οΈ
120+ Latihan
πŸ“˜ Minggu 1 β€” Fondasi (Hari 1-7)
Mengenal database, SELECT, WHERE, filter, sorting β€” pondasi yang kokoh
1
Pengenalan Database & SQL
Konsep, tabel, relasi, setup
2
SELECT & FROM
Mengambil data, alias, DISTINCT
3
WHERE & Operator
Filter, perbandingan, BETWEEN
4
Logika Kombinasi
AND, OR, NOT, IN
5
Pattern & NULL
LIKE, IS NULL, wildcard
6
Sorting & Paging
ORDER BY, LIMIT, OFFSET
7
Review & Mini Project
Latihan gabungan
πŸ“— Minggu 2 β€” Intermediate (Hari 8-14)
Agregasi, pengelompokan, dan menggabungkan tabel β€” mulai terasa powerful
8
Fungsi Agregat
COUNT, SUM, AVG, MIN, MAX
9
GROUP BY
Mengelompokkan data
10
HAVING
Filter setelah grouping
11
INNER JOIN
Gabung tabel, data cocok
12
LEFT & RIGHT JOIN
Semua data + relasi
13
Multi-JOIN & SELF JOIN
Join 3+ tabel, hierarki
14
Review & Mini Project
Laporan multi-tabel
πŸ“™ Minggu 3 β€” Advanced (Hari 15-21)
Subquery, manipulasi data, fungsi lanjutan β€” level profesional
15
Subquery di WHERE
Query bersarang
16
Subquery di FROM & EXISTS
Derived table, EXISTS
17
CASE WHEN & COALESCE
Logika kondisional
18
Fungsi String & Date
Manipulasi teks & tanggal
19
INSERT, UPDATE, DELETE
Manipulasi data (DML)
20
DDL & Transaksi
CREATE, ALTER, TRANSACTION
21
Review & Mini Project
Sistem CRUD lengkap
πŸ“• Minggu 4 β€” Expert (Hari 22-30)
View, CTE, Window Functions, analisis bisnis β€” menuju expert
22
VIEW & Virtual Table
Simpan query reusable
23
INDEX & Performance
Optimasi query
24
CTE (WITH Clause)
Common Table Expression
25
Window Functions I
ROW_NUMBER, RANK, DENSE_RANK
26
Window Functions II
LAG, LEAD, Running Total
27
Analisis Penjualan
Dashboard, MoM growth
28
Customer Analytics
RFM, segmentasi, CLV
29
Executive Reporting
Dashboard, cross-sell
30
Final Project & Cheat Sheet
Proyek akhir, referensi
βš™οΈ Persiapan β€” Setup Database Latihan di DBeaver
Lakukan ini sekali saja di awal. Database ini akan dipakai selama 30 hari.
1
Buka DBeaver β†’ Database β†’ New Database Connection
2
Pilih SQLite (tidak perlu install server apapun)
3
Klik Create β†’ simpan sebagai belajar_sql.db
4
Klik kanan database β†’ SQL Editor β†’ New SQL Script
5
Copy-paste & jalankan script di bawah (Ctrl+Enter / Cmd+Enter)
πŸ“¦ Script Database Latihan β€” Jalankan Semua
-- ╔═══════════════════════════════════════════╗
-- β•‘   DATABASE LATIHAN: SISTEM TOKO ONLINE    β•‘
-- β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•

CREATE TABLE pelanggan (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    nama VARCHAR(100) NOT NULL, email VARCHAR(100) UNIQUE,
    kota VARCHAR(50), umur INTEGER, jenis_kelamin VARCHAR(10),
    tanggal_daftar DATE, status VARCHAR(20) DEFAULT 'aktif'
);
CREATE TABLE kategori (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    nama_kategori VARCHAR(50) NOT NULL, deskripsi TEXT
);
CREATE TABLE produk (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    nama_produk VARCHAR(100) NOT NULL, kategori_id INTEGER,
    harga DECIMAL(12,2) NOT NULL, stok INTEGER DEFAULT 0,
    berat_gram INTEGER, tanggal_masuk DATE,
    FOREIGN KEY (kategori_id) REFERENCES kategori(id)
);
CREATE TABLE pesanan (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    pelanggan_id INTEGER NOT NULL, tanggal_pesan DATE NOT NULL,
    total_harga DECIMAL(15,2), status_pesanan VARCHAR(20) DEFAULT 'pending',
    metode_bayar VARCHAR(30), alamat_kirim TEXT,
    FOREIGN KEY (pelanggan_id) REFERENCES pelanggan(id)
);
CREATE TABLE detail_pesanan (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    pesanan_id INTEGER NOT NULL, produk_id INTEGER NOT NULL,
    jumlah INTEGER NOT NULL, harga_satuan DECIMAL(12,2) NOT NULL,
    subtotal DECIMAL(15,2),
    FOREIGN KEY (pesanan_id) REFERENCES pesanan(id),
    FOREIGN KEY (produk_id) REFERENCES produk(id)
);
CREATE TABLE karyawan (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    nama VARCHAR(100) NOT NULL, jabatan VARCHAR(50),
    departemen VARCHAR(50), gaji DECIMAL(12,2),
    tanggal_masuk DATE, manager_id INTEGER,
    FOREIGN KEY (manager_id) REFERENCES karyawan(id)
);

-- DATA SAMPLE
INSERT INTO kategori VALUES(1,'Elektronik','Gadget & elektronik'),(2,'Pakaian','Fashion'),(3,'Makanan','Snack & minuman'),(4,'Buku','Buku fisik & digital'),(5,'Olahraga','Perlengkapan olahraga');

INSERT INTO pelanggan (nama,email,kota,umur,jenis_kelamin,tanggal_daftar,status) VALUES
('Andi Pratama','andi@email.com','Jakarta',28,'Pria','2024-01-15','aktif'),
('Budi Santoso','budi@email.com','Bandung',35,'Pria','2024-02-20','aktif'),
('Citra Dewi','citra@email.com','Surabaya',24,'Wanita','2024-03-10','aktif'),
('Dina Rahma','dina@email.com','Jakarta',30,'Wanita','2024-01-25','nonaktif'),
('Eko Wijaya','eko@email.com','Medan',42,'Pria','2024-04-05','aktif'),
('Fitri Yani','fitri@email.com','Bandung',27,'Wanita','2024-05-12','aktif'),
('Gilang Ramadhan','gilang@email.com','Jakarta',31,'Pria','2024-03-18','aktif'),
('Hana Pertiwi','hana@email.com','Yogyakarta',29,'Wanita','2024-06-01','aktif'),
('Irfan Hakim','irfan@email.com','Surabaya',38,'Pria','2024-02-14','nonaktif'),
('Jasmine Putri','jasmine@email.com','Bali',26,'Wanita','2024-07-20','aktif'),
('Kurnia Sandi','kurnia@email.com','Semarang',33,'Pria','2024-04-22','aktif'),
('Lina Marlina','lina@email.com','Jakarta',45,'Wanita','2024-01-08','aktif'),
('Mega Sari',NULL,'Bandung',22,'Wanita','2024-08-15','aktif'),
('Nanda Putra','nanda@email.com','Medan',36,'Pria','2024-05-30','aktif'),
('Oscar Tan','oscar@email.com','Jakarta',29,'Pria','2024-09-01','aktif');

INSERT INTO produk (nama_produk,kategori_id,harga,stok,berat_gram,tanggal_masuk) VALUES
('Laptop Gaming ASUS',1,15000000,10,2500,'2024-01-01'),('Smartphone Samsung S24',1,12000000,25,200,'2024-02-15'),
('Headphone Sony WH-1000',1,3500000,30,250,'2024-01-20'),('Kaos Polos Premium',2,89000,200,200,'2024-03-01'),
('Celana Jeans Slim Fit',2,250000,150,500,'2024-02-10'),('Jaket Hoodie Unisex',2,175000,100,400,'2024-04-05'),
('Coklat Batang Import',3,35000,500,100,'2024-01-15'),('Kopi Arabica 250gr',3,85000,300,250,'2024-03-20'),
('Buku Pemrograman Python',4,120000,50,350,'2024-02-28'),('Novel Best Seller 2024',4,95000,80,300,'2024-05-10'),
('Sepatu Lari Nike',5,1200000,40,600,'2024-01-25'),('Matras Yoga Premium',5,350000,60,1500,'2024-04-15'),
('Tablet iPad Air',1,9500000,15,460,'2024-06-01'),('Kemeja Batik Modern',2,195000,120,250,'2024-03-15'),
('Teh Hijau Organik',3,45000,400,150,'2024-02-05');

INSERT INTO pesanan (pelanggan_id,tanggal_pesan,total_harga,status_pesanan,metode_bayar,alamat_kirim) VALUES
(1,'2024-06-01',15089000,'selesai','Transfer Bank','Jl. Sudirman 10, Jakarta'),(2,'2024-06-02',12250000,'selesai','E-Wallet','Jl. Braga 5, Bandung'),
(3,'2024-06-03',3585000,'dikirim','COD','Jl. Tunjungan 8, Surabaya'),(1,'2024-06-05',250000,'selesai','E-Wallet','Jl. Sudirman 10, Jakarta'),
(5,'2024-06-07',1200000,'selesai','Transfer Bank','Jl. SM Raja 15, Medan'),(6,'2024-06-10',175000,'pending','E-Wallet','Jl. Dago 20, Bandung'),
(7,'2024-06-12',9620000,'selesai','Kartu Kredit','Jl. Gatot Subroto 30, Jakarta'),(8,'2024-06-15',445000,'dikirim','Transfer Bank','Jl. Malioboro 12, Yogyakarta'),
(3,'2024-06-18',12095000,'selesai','Kartu Kredit','Jl. Tunjungan 8, Surabaya'),(10,'2024-06-20',350000,'pending','COD','Jl. Sunset Road 7, Bali'),
(11,'2024-06-22',15120000,'selesai','Transfer Bank','Jl. Pandanaran 5, Semarang'),(1,'2024-06-25',85000,'selesai','E-Wallet','Jl. Sudirman 10, Jakarta'),
(12,'2024-07-01',24500000,'selesai','Kartu Kredit','Jl. Kemang 18, Jakarta'),(2,'2024-07-03',350000,'dikirim','E-Wallet','Jl. Braga 5, Bandung'),
(14,'2024-07-05',1289000,'selesai','Transfer Bank','Jl. SM Raja 22, Medan'),(15,'2024-07-08',3500000,'pending','Kartu Kredit','Jl. Rasuna Said 9, Jakarta'),
(7,'2024-07-10',250000,'selesai','COD','Jl. Gatot Subroto 30, Jakarta'),(6,'2024-07-12',12000000,'dikirim','Transfer Bank','Jl. Dago 20, Bandung'),
(8,'2024-07-15',95000,'selesai','E-Wallet','Jl. Malioboro 12, Yogyakarta'),(3,'2024-07-18',1550000,'selesai','Kartu Kredit','Jl. Tunjungan 8, Surabaya');

INSERT INTO detail_pesanan (pesanan_id,produk_id,jumlah,harga_satuan,subtotal) VALUES
(1,1,1,15000000,15000000),(1,4,1,89000,89000),(2,2,1,12000000,12000000),(2,5,1,250000,250000),
(3,3,1,3500000,3500000),(3,8,1,85000,85000),(4,5,1,250000,250000),(5,11,1,1200000,1200000),
(6,6,1,175000,175000),(7,13,1,9500000,9500000),(7,9,1,120000,120000),(8,12,1,350000,350000),
(8,10,1,95000,95000),(9,2,1,12000000,12000000),(9,10,1,95000,95000),(10,12,1,350000,350000),
(11,1,1,15000000,15000000),(11,9,1,120000,120000),(12,8,1,85000,85000),(13,1,1,15000000,15000000),
(13,13,1,9500000,9500000),(14,12,1,350000,350000),(15,11,1,1200000,1200000),(15,4,1,89000,89000),
(16,3,1,3500000,3500000),(17,5,1,250000,250000),(18,2,1,12000000,12000000),(19,10,1,95000,95000),
(20,11,1,1200000,1200000),(20,12,1,350000,350000);

INSERT INTO karyawan (nama,jabatan,departemen,gaji,tanggal_masuk,manager_id) VALUES
('Rudi Hartono','CEO','Direksi',50000000,'2020-01-01',NULL),('Sari Indah','CTO','Teknologi',40000000,'2020-03-15',1),
('Tono Sugiarto','CFO','Keuangan',40000000,'2020-02-01',1),('Umar Faruq','Lead Dev','Teknologi',25000000,'2021-06-01',2),
('Vina Amelia','Senior Dev','Teknologi',20000000,'2021-09-15',4),('Wahyu Prabowo','Junior Dev','Teknologi',12000000,'2023-01-10',4),
('Xena Putri','Finance Mgr','Keuangan',22000000,'2021-04-01',3),('Yogi Saputra','Accountant','Keuangan',15000000,'2022-07-20',7),
('Zahra Nabila','Marketing Mgr','Marketing',22000000,'2021-05-10',1),('Arif Budiman','Marketing Staff','Marketing',10000000,'2023-03-01',9),
('Bella Safitri','HR Manager','HRD',22000000,'2021-08-15',1),('Chandra Wijaya','HR Staff','HRD',10000000,'2023-06-01',11);
πŸ’‘
Tips DBeaver: Highlight (blok) query β†’ Ctrl+Enter (Mac: Cmd+Enter) untuk menjalankan. Jalankan script di atas sekaligus.

πŸ“˜ Minggu 1 β€” Fondasi

Mengenal database, membaca data, filter, dan sorting

1

Pengenalan Database & SQL

Konsep dasar Β· Tabel Β· Kolom Β· Baris Β· Relasi

Apa itu Database & SQL?
Database = lemari arsip digital yang menyimpan data secara terstruktur. SQL (Structured Query Language) = bahasa untuk berkomunikasi dengan database. Kamu "bertanya", database memberi "jawaban".
Analogi Database
Istilah Analogi Contoh di Excel
Database Lemari arsip File workbook
Tabel Laci/folder Sheet
Kolom Jenis info (Nama, Alamat) Header kolom
Baris (Row) Satu kartu data Satu baris data
Primary Key (PK) Nomor KTP (unik) ID unik tiap baris
Foreign Key (FK) Referensi ke tabel lain VLOOKUP ke sheet lain
DQL
SELECT
Baca data
DML
INSERT UPDATE DELETE
Ubah data
DDL
CREATE ALTER DROP
Ubah struktur
DCL
GRANT REVOKE
Hak akses
Relasi antar tabel kita
   pelanggan ──────► pesanan ──────► detail_pesanan
                                          β”‚
   kategori ──────► produk β—„β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
   karyawan (self-reference: manager_id β†’ karyawan.id)
πŸ’‘
Tugas Hari 1: Jalankan script setup di atas. Lalu ketik SELECT * FROM pelanggan; dan tekan Ctrl+Enter. Jika muncul 15 baris data, kamu siap!
2

SELECT & FROM

Mengambil data Β· Kolom tertentu Β· AS alias Β· DISTINCT

SELECT β€” Perintah Paling Sering Dipakai
SELECT = ambil/baca data dari tabel. Ini perintah yang kamu pakai 90% dari waktu.
Dasar SELECT
-- Ambil SEMUA kolom (* = semua)
SELECT * FROM pelanggan;

-- Ambil kolom tertentu saja (lebih efisien)
SELECT nama, email, kota FROM pelanggan;

-- Beri nama alias dengan AS
SELECT nama AS nama_pelanggan, email AS alamat_email FROM pelanggan;

-- Hitung kolom baru
SELECT nama_produk, harga, stok, harga * stok AS nilai_total FROM produk;

-- Gabung teks (concatenation)
SELECT nama || ' - ' || kota AS info FROM pelanggan;

DISTINCT β€” Hapus Duplikat

SELECT DISTINCT kota FROM pelanggan;  -- Kota unik saja
SELECT DISTINCT kota, jenis_kelamin FROM pelanggan; -- Kombinasi unik
πŸ‹οΈ Latihan Hari 2 (5 soal)
1. Tampilkan semua data dari tabel produk
2. Tampilkan hanya nama dan harga produk
3. Tampilkan kota-kota unik pelanggan
4. Tampilkan nama produk dan harga setelah diskon 10%
5. Tampilkan info pelanggan format: "Nama (Kota)"
βœ… Jawaban
-- 1 SELECT * FROM produk;
-- 2 SELECT nama_produk, harga FROM produk;
-- 3 SELECT DISTINCT kota FROM pelanggan;
-- 4 SELECT nama_produk, harga, harga*0.9 AS harga_diskon FROM produk;
-- 5 SELECT nama||' ('||kota||')' AS info FROM pelanggan;
3

WHERE β€” Menyaring Data

Operator = != > < BETWEEN

WHERE β€” Filter Baris
WHERE = tentukan syarat. Hanya baris yang memenuhi syarat yang ditampilkan.
Operator Arti Contoh
= Sama dengan kota = 'Jakarta'
!= atau <> Tidak sama kota != 'Jakarta'
> < >= <= Perbandingan umur > 30
BETWEEN x AND y Dalam rentang harga BETWEEN 50000 AND 500000
Contoh WHERE
SELECT * FROM pelanggan WHERE kota = 'Jakarta';
SELECT nama, umur FROM pelanggan WHERE umur > 30;
SELECT nama_produk, harga FROM produk WHERE harga BETWEEN 100000 AND 500000;
SELECT * FROM pesanan WHERE status_pesanan = 'selesai';
⚠️
Teks harus pakai kutip satu: 'Jakarta'. Angka tidak perlu: 30
πŸ‹οΈ Latihan Hari 3 (5 soal)
1. Pelanggan wanita
2. Produk harga di atas 1 juta
3. Pelanggan umur 25-35
4. Pesanan bukan status 'pending'
5. Produk stok kurang dari 30
βœ… Jawaban
-- 1 SELECT * FROM pelanggan WHERE jenis_kelamin='Wanita';
-- 2 SELECT * FROM produk WHERE harga>1000000;
-- 3 SELECT * FROM pelanggan WHERE umur BETWEEN 25 AND 35;
-- 4 SELECT * FROM pesanan WHERE status_pesanan!='pending';
-- 5 SELECT nama_produk,stok FROM produk WHERE stok<30;
4

Logika Kombinasi

AND Β· OR Β· NOT Β· IN Β· NOT IN

AND, OR, NOT, IN
Kombinasi Kondisi
-- AND: kedua syarat harus benar
SELECT * FROM pelanggan WHERE kota='Jakarta' AND jenis_kelamin='Wanita';

-- OR: salah satu benar cukup
SELECT * FROM pelanggan WHERE kota='Jakarta' OR kota='Bandung';

-- ⚠️ PENTING: pakai () saat gabung AND + OR
SELECT * FROM pelanggan 
WHERE (kota='Jakarta' OR kota='Bandung') AND umur>25;

-- IN: lebih ringkas dari banyak OR
SELECT * FROM pelanggan WHERE kota IN('Jakarta','Bandung','Surabaya');

-- NOT IN: yang TIDAK di daftar
SELECT * FROM pelanggan WHERE kota NOT IN('Jakarta','Bandung');
⚠️
Tanpa tanda kurung: A OR B AND C = A OR (B AND C). AND diproses duluan!
5

Pattern Matching & NULL

LIKE Β· Wildcard % _ Β· IS NULL Β· IS NOT NULL

LIKE β€” Cari Pola Teks
Pattern Arti Contoh Cocok
'A%' Diawali A Andi, Ahmad
'%Putr%' Mengandung "Putr" Jasmine Putri, Nanda Putra
'%a' Diakhiri a Citra Dewi→tidak, Mega→tidak
'_i%' Huruf ke-2 = i Dina, Lina
SELECT * FROM pelanggan WHERE nama LIKE 'A%';       -- Diawali A
SELECT * FROM pelanggan WHERE nama LIKE '%Putr%';   -- Mengandung Putr
SELECT * FROM produk WHERE nama_produk LIKE '%Premium%';

IS NULL / IS NOT NULL

SELECT * FROM pelanggan WHERE email IS NULL;      -- Tanpa email
SELECT * FROM pelanggan WHERE email IS NOT NULL;  -- Punya email
🚫
Jangan pakai = NULL! NULL bukan nilai, tapi "ketiadaan data". Harus pakai IS NULL.
6

Sorting & Paging

ORDER BY Β· ASC Β· DESC Β· LIMIT Β· OFFSET

ORDER BY, LIMIT, OFFSET
Sorting & Paging
-- A-Z (ASC = ascending, default)
SELECT * FROM pelanggan ORDER BY nama ASC;

-- Termahal dulu
SELECT nama_produk, harga FROM produk ORDER BY harga DESC;

-- Multi-sort: kota A-Z, lalu umur besar dulu
SELECT * FROM pelanggan ORDER BY kota ASC, umur DESC;

-- Top 3 produk termahal
SELECT nama_produk, harga FROM produk ORDER BY harga DESC LIMIT 3;

-- Halaman 2 (skip 5, ambil 5)
SELECT * FROM pelanggan LIMIT 5 OFFSET 5;
7

Review & Mini Project Minggu 1

Gabungkan semua yang dipelajari

πŸ“‹ Ringkasan Minggu 1

  • SELECT kolom FROM tabel β€” ambil data
  • WHERE kondisi β€” filter baris
  • AND / OR / NOT / IN β€” gabung kondisi
  • LIKE '%pola%' β€” cari pola teks
  • IS NULL / IS NOT NULL β€” cek data kosong
  • ORDER BY kolom DESC β€” urutkan
  • LIMIT n OFFSET m β€” batasi & paging
πŸ‹οΈ Mini Project Minggu 1 (7 soal)
1. 5 pelanggan wanita termuda dari Jakarta atau Bandung
2. Produk yang namanya mengandung 'a', harga di bawah 500rb
3. Pesanan 'selesai' via 'Kartu Kredit', urutkan terbesar
4. 3 produk termurah dari kategori pakaian (kategori_id=2)
5. Pelanggan dari luar Jakarta, umur 25-35
6. Pesanan total > 5 juta, tampilkan 5 terbesar
7. Pelanggan yang tidak punya email
βœ… Jawaban
-- 1 SELECT * FROM pelanggan WHERE jenis_kelamin='Wanita' AND kota IN('Jakarta','Bandung') ORDER BY umur LIMIT 5;
-- 2 SELECT * FROM produk WHERE nama_produk LIKE '%a%' AND harga<500000;
-- 3 SELECT * FROM pesanan WHERE status_pesanan='selesai' AND metode_bayar='Kartu Kredit' ORDER BY total_harga DESC;
-- 4 SELECT * FROM produk WHERE kategori_id=2 ORDER BY harga LIMIT 3;
-- 5 SELECT * FROM pelanggan WHERE kota!='Jakarta' AND umur BETWEEN 25 AND 35;
-- 6 SELECT * FROM pesanan WHERE total_harga>5000000 ORDER BY total_harga DESC LIMIT 5;
-- 7 SELECT * FROM pelanggan WHERE email IS NULL;

πŸ“— Minggu 2 β€” Intermediate

Agregasi, pengelompokan, dan menggabungkan tabel

8

Fungsi Agregat

COUNT Β· SUM Β· AVG Β· MIN Β· MAX

Fungsi Agregat β€” Hitung Banyak Baris Sekaligus
Fungsi agregat mengambil banyak baris β†’ menghasilkan satu nilai.
COUNT
Hitung baris
SUM
Jumlahkan
AVG
Rata-rata
MIN
Terkecil
MAX
Terbesar
Fungsi Agregat
SELECT COUNT(*) AS total_pelanggan FROM pelanggan;
SELECT COUNT(email) AS punya_email FROM pelanggan; -- NULL tak dihitung!
SELECT SUM(total_harga) AS pendapatan FROM pesanan;
SELECT AVG(umur) AS rata_umur FROM pelanggan;
SELECT MIN(harga) AS termurah, MAX(harga) AS termahal FROM produk;

-- Gabung semua sekaligus
SELECT COUNT(*) AS total, SUM(stok) AS stok,
  AVG(harga) AS rata, MIN(harga) AS min, MAX(harga) AS max
FROM produk;
9

GROUP BY

Mengelompokkan data Β· Hitung per grup

GROUP BY β€” Hitung Per Kelompok
Bayangkan tumpukan kartu. GROUP BY kota = pisahkan per kota, hitung tiap tumpukan.
GROUP BY
-- Jumlah pelanggan per kota
SELECT kota, COUNT(*) AS jumlah FROM pelanggan GROUP BY kota;

-- Total penjualan per metode bayar
SELECT metode_bayar, COUNT(*) AS trx, SUM(total_harga) AS total
FROM pesanan GROUP BY metode_bayar;

-- Produk per kategori
SELECT kategori_id, COUNT(*) AS jml, AVG(harga) AS rata
FROM produk GROUP BY kategori_id;

-- Total belanja per pelanggan, terbesar dulu
SELECT pelanggan_id, COUNT(*) AS orders, SUM(total_harga) AS total
FROM pesanan GROUP BY pelanggan_id ORDER BY total DESC;
⚠️
Aturan Emas: Kolom di SELECT yang BUKAN fungsi agregat HARUS ada di GROUP BY!
10

HAVING β€” Filter Setelah Group

WHERE vs HAVING Β· Urutan eksekusi SQL

HAVING vs WHERE
WHERE filter sebelum grouping. HAVING filter setelah grouping.
HAVING
-- Kota dengan > 2 pelanggan
SELECT kota, COUNT(*) AS jml
FROM pelanggan GROUP BY kota HAVING COUNT(*)>2;

-- WHERE + HAVING bersama
SELECT pelanggan_id, SUM(total_harga) AS total
FROM pesanan
WHERE status_pesanan = 'selesai'      -- filter BARIS dulu
GROUP BY pelanggan_id
HAVING SUM(total_harga) > 5000000   -- lalu filter GRUP
ORDER BY total DESC;
⚑ Urutan Eksekusi SQL (Sangat Penting!)
FROM→WHERE→GROUP BY→HAVING→SELECT→ORDER BY→LIMIT
11

INNER JOIN

Gabung 2 tabel Β· Data yang cocok Β· Alias

INNER JOIN β€” Hanya Data yang Cocok
JOIN menggabungkan data dari 2+ tabel via kolom penghubung (FK β†’ PK).
INNER JOIN
-- Pesanan + nama pelanggannya
SELECT pes.id, pel.nama, pes.tanggal_pesan, pes.total_harga
FROM pesanan pes
INNER JOIN pelanggan pel ON pes.pelanggan_id = pel.id;

-- Produk + nama kategorinya
SELECT pr.nama_produk, k.nama_kategori, pr.harga
FROM produk pr
INNER JOIN kategori k ON pr.kategori_id = k.id;
πŸ’‘
Pakai alias singkat (pes, pel, pr, k) agar mudah dibaca. JOIN tanpa awalan = INNER JOIN.
12

LEFT JOIN

Semua data kiri Β· Temukan yang tidak punya relasi

LEFT JOIN β€” Semua Kiri + Cocok Kanan
Jenis Hasil Kapan Pakai
INNER JOIN Hanya yang cocok Hanya butuh data yang punya relasi
LEFT JOIN Semua kiri + cocok kanan (NULL jika tak ada) Mau lihat semua, termasuk yang tanpa relasi
LEFT JOIN
-- Semua pelanggan + pesanannya (termasuk yg belum pesan)
SELECT pel.nama, pes.id, pes.total_harga
FROM pelanggan pel
LEFT JOIN pesanan pes ON pel.id = pes.pelanggan_id;

-- πŸ”₯ Trik populer: cari yang BELUM PERNAH pesan
SELECT pel.nama, pel.email
FROM pelanggan pel
LEFT JOIN pesanan pes ON pel.id = pes.pelanggan_id
WHERE pes.id IS NULL;
13

Multi-JOIN & SELF JOIN

Join 3+ tabel Β· Hierarki Β· JOIN + Agregat

Multi-JOIN & SELF JOIN
Join 4 tabel: siapa beli apa
SELECT pel.nama, pr.nama_produk, k.nama_kategori, dp.subtotal
FROM detail_pesanan dp
JOIN pesanan pes ON dp.pesanan_id = pes.id
JOIN pelanggan pel ON pes.pelanggan_id = pel.id
JOIN produk pr ON dp.produk_id = pr.id
JOIN kategori k ON pr.kategori_id = k.id;
SELF JOIN: Karyawan + Manager
SELECT k.nama AS karyawan, k.jabatan, m.nama AS manager
FROM karyawan k
LEFT JOIN karyawan m ON k.manager_id = m.id;
JOIN + GROUP BY = Super Powerful
-- Total belanja per pelanggan (dengan nama)
SELECT pel.nama, COUNT(pes.id) AS orders,
  COALESCE(SUM(pes.total_harga),0) AS total
FROM pelanggan pel
LEFT JOIN pesanan pes ON pel.id=pes.pelanggan_id
GROUP BY pel.id, pel.nama ORDER BY total DESC;

-- Penjualan per kategori
SELECT k.nama_kategori, SUM(dp.subtotal) AS pendapatan
FROM kategori k JOIN produk pr ON k.id=pr.kategori_id
JOIN detail_pesanan dp ON pr.id=dp.produk_id
GROUP BY k.nama_kategori ORDER BY pendapatan DESC;
14

Review & Mini Project Minggu 2

Agregat + JOIN = Laporan multi-tabel

πŸ‹οΈ Mini Project Minggu 2 (7 soal)
1. Jumlah pelanggan per kota, hanya > 1 pelanggan
2. Top 5 pelanggan by total belanja (nama!)
3. Kategori paling banyak terjual
4. Produk yang belum pernah dipesan
5. Karyawan + manager + gaji
6. Total penjualan per bulan
7. Metode bayar paling populer
βœ… Jawaban
-- 1 SELECT kota,COUNT(*) AS j FROM pelanggan GROUP BY kota HAVING COUNT(*)>1;
-- 2 SELECT pel.nama,SUM(pes.total_harga) AS t FROM pelanggan pel JOIN pesanan pes ON pel.id=pes.pelanggan_id GROUP BY pel.id ORDER BY t DESC LIMIT 5;
-- 3 SELECT k.nama_kategori,SUM(dp.jumlah) AS terjual FROM kategori k JOIN produk pr ON k.id=pr.kategori_id JOIN detail_pesanan dp ON pr.id=dp.produk_id GROUP BY k.nama_kategori ORDER BY terjual DESC;
-- 4 SELECT pr.nama_produk FROM produk pr LEFT JOIN detail_pesanan dp ON pr.id=dp.produk_id WHERE dp.id IS NULL;
-- 5 SELECT k.nama,k.jabatan,COALESCE(m.nama,'-') AS mgr,k.gaji FROM karyawan k LEFT JOIN karyawan m ON k.manager_id=m.id;
-- 6 SELECT SUBSTR(tanggal_pesan,1,7) AS bln,SUM(total_harga) AS t FROM pesanan GROUP BY bln ORDER BY bln;
-- 7 SELECT metode_bayar,COUNT(*) AS j FROM pesanan GROUP BY metode_bayar ORDER BY j DESC LIMIT 1;

πŸ“™ Minggu 3 β€” Advanced

Subquery, manipulasi data, fungsi lanjutan

15

Subquery di WHERE

Query bersarang Β· IN + subquery

Subquery β€” Query dalam Query
"Tampilkan produk yang harganya di atas rata-rata" β†’ perlu hitung rata-rata dulu β†’ subquery!
Subquery di WHERE
-- Produk di atas harga rata-rata
SELECT nama_produk, harga FROM produk
WHERE harga > (SELECT AVG(harga) FROM produk);

-- Pelanggan yang pernah beli produk elektronik
SELECT DISTINCT pel.nama FROM pelanggan pel
WHERE pel.id IN (
    SELECT pes.pelanggan_id FROM pesanan pes
    JOIN detail_pesanan dp ON pes.id=dp.pesanan_id
    JOIN produk pr ON dp.produk_id=pr.id
    WHERE pr.kategori_id = 1
);
16

Subquery di FROM & EXISTS

Derived table Β· EXISTS / NOT EXISTS

Derived Table & EXISTS
Subquery di FROM (Derived Table)
-- Rata-rata jumlah pesanan per pelanggan
SELECT AVG(jml) AS rata_pesanan
FROM (SELECT pelanggan_id, COUNT(*) AS jml
      FROM pesanan GROUP BY pelanggan_id) AS r;
EXISTS / NOT EXISTS
-- Pelanggan yang PERNAH pesan
SELECT nama FROM pelanggan pel
WHERE EXISTS (SELECT 1 FROM pesanan pes WHERE pes.pelanggan_id=pel.id);

-- Pelanggan yang BELUM PERNAH pesan
SELECT nama FROM pelanggan pel
WHERE NOT EXISTS (SELECT 1 FROM pesanan pes WHERE pes.pelanggan_id=pel.id);
17

CASE WHEN & COALESCE

Logika kondisional Β· IF-ELSE Β· Handle NULL

CASE WHEN β€” IF-ELSE di SQL
CASE WHEN
-- Kategorisasi harga
SELECT nama_produk, harga,
    CASE
        WHEN harga < 100000 THEN 'Murah'
        WHEN harga <= 1000000 THEN 'Menengah'
        WHEN harga <= 10000000 THEN 'Mahal'
        ELSE 'Premium'
    END AS level_harga
FROM produk ORDER BY harga;

-- Pivot: hitung per status dalam 1 baris
SELECT
    COUNT(CASE WHEN status_pesanan='selesai' THEN 1 END) AS selesai,
    COUNT(CASE WHEN status_pesanan='dikirim' THEN 1 END) AS dikirim,
    COUNT(CASE WHEN status_pesanan='pending' THEN 1 END) AS pending
FROM pesanan;
COALESCE β€” Ganti NULL
SELECT nama, COALESCE(email, 'Tidak ada email') AS email FROM pelanggan;
18

Fungsi String & Date

UPPER Β· LOWER Β· SUBSTR Β· STRFTIME Β· ROUND

Fungsi Bawaan SQL
String
SELECT UPPER(nama), LOWER(email), LENGTH(nama) FROM pelanggan;
SELECT SUBSTR(nama,1,5) AS potong FROM pelanggan;
SELECT REPLACE(email,'@email.com','@gmail.com') FROM pelanggan;
SELECT nama||' ('||kota||')' AS info FROM pelanggan;
Tanggal & Angka
SELECT STRFTIME('%Y',tanggal_pesan) AS tahun,
       STRFTIME('%m',tanggal_pesan) AS bulan FROM pesanan;
SELECT nama_produk, harga, ROUND(harga*1.11,0) AS ppn FROM produk;
19

INSERT, UPDATE, DELETE

Tambah Β· Ubah Β· Hapus data (DML)

DML β€” Manipulasi Data
INSERT
INSERT INTO pelanggan (nama,email,kota,umur,jenis_kelamin,tanggal_daftar)
VALUES ('Putri H','putri@email.com','Makassar',25,'Wanita','2024-10-01');

-- Insert banyak sekaligus
INSERT INTO pelanggan (nama,email,kota,umur,jenis_kelamin,tanggal_daftar) VALUES
('Rizky A','rizky@email.com','Palembang',32,'Pria','2024-10-05'),
('Sinta D','sinta@email.com','Bali',28,'Wanita','2024-10-10');
UPDATE
UPDATE pelanggan SET kota='Tangerang' WHERE id=1;
UPDATE produk SET harga=harga*1.1 WHERE kategori_id=3; -- Makanan +10%
DELETE
SELECT * FROM pelanggan WHERE id=16; -- Cek dulu!
DELETE FROM pelanggan WHERE id=16;    -- Baru hapus
🚫
UPDATE/DELETE tanpa WHERE = mengubah/hapus SEMUA baris! Selalu SELECT dulu untuk verifikasi.
20

DDL & Transaksi

CREATE TABLE Β· ALTER Β· DROP Β· TRANSACTION

DDL & TRANSACTION
CREATE TABLE & ALTER
CREATE TABLE review_produk (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    produk_id INTEGER NOT NULL,
    pelanggan_id INTEGER NOT NULL,
    rating INTEGER CHECK(rating BETWEEN 1 AND 5),
    komentar TEXT,
    tanggal_review DATE DEFAULT(DATE('now'))
);

ALTER TABLE pelanggan ADD COLUMN no_telepon VARCHAR(15);
DROP TABLE IF EXISTS tabel_temp;
TRANSACTION β€” Operasi Aman
BEGIN TRANSACTION;
    INSERT INTO pesanan (...) VALUES (...);
    INSERT INTO detail_pesanan (...) VALUES (...);
    UPDATE produk SET stok=stok-1 WHERE id=1;
COMMIT;   -- Simpan semua (atau ROLLBACK untuk batalkan)
21

Review & Mini Project Minggu 3

Subquery + CASE + DML

πŸ‹οΈ Mini Project Minggu 3 (5 soal)
1. Produk di atas harga rata-rata + kategorinya
2. Kolom segmentasi umur (Gen Z <25, Millennial 25-34, Gen X 35+)
3. Pelanggan yang pernah beli pakaian (via subquery)
4. Buat kolom baru harga+ppn 11% dan level_harga
5. Insert 3 review, tampilkan rata-rata rating per produk
βœ… Jawaban
-- 1 SELECT pr.nama_produk,k.nama_kategori,pr.harga FROM produk pr JOIN kategori k ON pr.kategori_id=k.id WHERE pr.harga>(SELECT AVG(harga) FROM produk);
-- 2 SELECT nama,umur,CASE WHEN umur<25 THEN 'Gen Z' WHEN umur<=34 THEN 'Millennial' ELSE 'Gen X' END AS gen FROM pelanggan;
-- 3 SELECT DISTINCT pel.nama FROM pelanggan pel WHERE pel.id IN(SELECT pes.pelanggan_id FROM pesanan pes JOIN detail_pesanan dp ON pes.id=dp.pesanan_id JOIN produk pr ON dp.produk_id=pr.id WHERE pr.kategori_id=2);
-- 4 SELECT nama_produk,harga,ROUND(harga*1.11,0) AS ppn,CASE WHEN harga<100000 THEN 'Murah' WHEN harga<=1000000 THEN 'Menengah' ELSE 'Mahal' END AS lvl FROM produk;
-- 5 INSERT INTO review_produk(produk_id,pelanggan_id,rating,komentar) VALUES(1,1,5,'Bagus'),(1,3,4,'Oke'),(2,2,5,'Mantap');
SELECT produk_id,AVG(rating) AS avg_rate FROM review_produk GROUP BY produk_id;

πŸ“• Minggu 4 β€” Expert

View, CTE, Window Functions, dan analisis bisnis nyata

22

VIEW β€” Tabel Virtual

Simpan query Β· Reusable Β· Abstraksi

VIEW β€” Query Tersimpan
View = query yang disimpan dan bisa dipakai seperti tabel biasa. Hemat waktu!
VIEW
CREATE VIEW v_ringkasan_pelanggan AS
SELECT pel.id, pel.nama, pel.kota,
    COUNT(pes.id) AS total_pesanan,
    COALESCE(SUM(pes.total_harga),0) AS total_belanja
FROM pelanggan pel
LEFT JOIN pesanan pes ON pel.id=pes.pelanggan_id
GROUP BY pel.id, pel.nama, pel.kota;

-- Pakai seperti tabel biasa!
SELECT * FROM v_ringkasan_pelanggan WHERE total_belanja>10000000;
SELECT * FROM v_ringkasan_pelanggan ORDER BY total_belanja DESC LIMIT 5;
23

INDEX & Performance

Percepat query Β· EXPLAIN Β· Kapan pakai

INDEX β€” Percepat Pencarian Data
Index = indeks di belakang buku. Bantu database cari data tanpa scan seluruh tabel.
CREATE INDEX idx_pel_kota ON pelanggan(kota);
CREATE INDEX idx_pes_pel ON pesanan(pelanggan_id);
CREATE INDEX idx_pes_tgl ON pesanan(tanggal_pesan);

-- Lihat apakah index terpakai
EXPLAIN QUERY PLAN SELECT * FROM pelanggan WHERE kota='Jakarta';
πŸ’‘
Buat index di: kolom WHERE, kolom JOIN (FK), ORDER BY. Jangan di: tabel kecil, kolom sering UPDATE.
24

CTE (WITH Clause)

Common Table Expression Β· Pecah query kompleks

CTE β€” Tabel Sementara dalam 1 Query
CTE memecah query kompleks jadi langkah-langkah yang mudah dibaca. Lebih rapi dari subquery bersarang.
CTE Tunggal
WITH pelanggan_vip AS (
    SELECT pelanggan_id, SUM(total_harga) AS total
    FROM pesanan GROUP BY pelanggan_id
    HAVING SUM(total_harga) > 10000000
)
SELECT pel.nama, pel.kota, vip.total
FROM pelanggan_vip vip JOIN pelanggan pel ON vip.pelanggan_id=pel.id;
Multiple CTE
WITH
ringkasan AS (
    SELECT produk_id, SUM(jumlah) AS terjual, SUM(subtotal) AS rev
    FROM detail_pesanan GROUP BY produk_id
),
rata AS (SELECT AVG(rev) AS avg_rev FROM ringkasan)
SELECT pr.nama_produk, r.terjual, r.rev,
    CASE WHEN r.rev>ra.avg_rev THEN 'Di Atas RataΒ²' ELSE 'Di Bawah' END AS performa
FROM ringkasan r JOIN produk pr ON r.produk_id=pr.id CROSS JOIN rata ra
ORDER BY r.rev DESC;
25

Window Functions I

ROW_NUMBER Β· RANK Β· DENSE_RANK Β· PARTITION BY

Window Functions β€” Analisis Tanpa Grouping
Kalkulasi pada sekumpulan baris tanpa menggabungkan (beda dari GROUP BY). Setiap baris tetap terlihat!
Ranking
-- Ranking global by harga
SELECT nama_produk, harga,
    ROW_NUMBER() OVER(ORDER BY harga DESC) AS ranking
FROM produk;

-- Ranking PER KATEGORI
SELECT k.nama_kategori, pr.nama_produk, pr.harga,
    ROW_NUMBER() OVER(PARTITION BY pr.kategori_id ORDER BY pr.harga DESC) AS rank_di_kat
FROM produk pr JOIN kategori k ON pr.kategori_id=k.id;
Fungsi Kegunaan Jika nilai sama
ROW_NUMBER() Nomor urut unik 1, 2, 3, 4
RANK() Ranking 1, 2, 2, 4 (skip)
DENSE_RANK() Ranking padat 1, 2, 2, 3 (no skip)
26

Window Functions II

LAG Β· LEAD Β· Running Total Β· NTILE

LAG, LEAD, Running Total
Running Total & Perbandingan
-- Running total (akumulasi penjualan)
SELECT tanggal_pesan, total_harga,
    SUM(total_harga) OVER(ORDER BY tanggal_pesan) AS akumulasi
FROM pesanan WHERE status_pesanan='selesai';

-- LAG: bandingkan dengan baris sebelumnya
SELECT tanggal_pesan, total_harga,
    LAG(total_harga) OVER(ORDER BY tanggal_pesan) AS sebelum,
    total_harga - LAG(total_harga) OVER(ORDER BY tanggal_pesan) AS selisih
FROM pesanan WHERE status_pesanan='selesai';

-- NTILE: bagi ke 4 grup (quartile)
SELECT nama, umur, NTILE(4) OVER(ORDER BY umur) AS quartile FROM pelanggan;
Fungsi Kegunaan
LAG(col, n) Nilai n baris sebelumnya
LEAD(col, n) Nilai n baris sesudahnya
SUM() OVER() Running total / akumulasi
NTILE(n) Bagi ke n grup sama rata
27

Analisis Penjualan

Dashboard Β· MoM Growth Β· Kontribusi %

Studi Kasus: Dashboard Penjualan
Month-over-Month Growth
WITH bulanan AS (
    SELECT SUBSTR(tanggal_pesan,1,7) AS bulan, SUM(total_harga) AS total
    FROM pesanan GROUP BY SUBSTR(tanggal_pesan,1,7)
)
SELECT bulan, total,
    LAG(total) OVER(ORDER BY bulan) AS bulan_lalu,
    ROUND((total-LAG(total) OVER(ORDER BY bulan))*100.0/
        LAG(total) OVER(ORDER BY bulan),2) AS growth_pct
FROM bulanan;
Kontribusi % Per Metode Bayar
WITH gt AS (SELECT SUM(total_harga) AS v FROM pesanan WHERE status_pesanan='selesai')
SELECT metode_bayar, COUNT(*) AS trx, SUM(total_harga) AS rev,
    ROUND(SUM(total_harga)*100.0/(SELECT v FROM gt),2) AS persen
FROM pesanan WHERE status_pesanan='selesai'
GROUP BY metode_bayar ORDER BY rev DESC;
28

Customer Analytics

RFM Segmentasi Β· Repeat vs One-time

Segmentasi Pelanggan (RFM)
Recency (kapan terakhir beli), Frequency (seberapa sering), Monetary (total belanja).
RFM Segmentation
WITH rfm AS (
    SELECT pel.id,pel.nama,pel.kota,
        COUNT(pes.id) AS frequency,
        SUM(pes.total_harga) AS monetary,
        MAX(pes.tanggal_pesan) AS last_order
    FROM pelanggan pel
    LEFT JOIN pesanan pes ON pel.id=pes.pelanggan_id
    GROUP BY pel.id,pel.nama,pel.kota
)
SELECT *, CASE
    WHEN monetary>15000000 AND frequency>=3 THEN 'πŸ† VIP'
    WHEN monetary>5000000 THEN '⭐ Premium'
    WHEN monetary>0 THEN 'πŸ‘€ Regular'
    ELSE 'πŸ’€ Inactive'
END AS segmen FROM rfm ORDER BY monetary DESC;
29

Executive Reporting

Dashboard Β· Cross-sell Β· All-in-one query

Executive Dashboard & Cross-Sell
All-in-one Executive Summary
WITH
sales AS (SELECT COUNT(*) AS orders,SUM(total_harga) AS rev,ROUND(AVG(total_harga),0) AS aov
    FROM pesanan WHERE status_pesanan='selesai'),
top_p AS (SELECT pr.nama_produk,SUM(dp.subtotal) AS r FROM detail_pesanan dp
    JOIN produk pr ON dp.produk_id=pr.id GROUP BY pr.id ORDER BY r DESC LIMIT 1),
top_c AS (SELECT pel.nama,SUM(pes.total_harga) AS b FROM pesanan pes
    JOIN pelanggan pel ON pes.pelanggan_id=pel.id GROUP BY pel.id ORDER BY b DESC LIMIT 1)
SELECT s.*,tp.nama_produk AS top_produk,tc.nama AS top_pelanggan,tc.b AS belanja
FROM sales s CROSS JOIN top_p tp CROSS JOIN top_c tc;
Cross-Sell: Sering Dibeli Bersamaan
SELECT p1.nama_produk AS produk_1, p2.nama_produk AS produk_2,
    COUNT(*) AS bareng
FROM detail_pesanan d1
JOIN detail_pesanan d2 ON d1.pesanan_id=d2.pesanan_id AND d1.produk_id<d2.produk_id
JOIN produk p1 ON d1.produk_id=p1.id
JOIN produk p2 ON d2.produk_id=p2.id
GROUP BY p1.nama_produk,p2.nama_produk ORDER BY bareng DESC;
30

Final Project & Cheat Sheet

Proyek akhir Β· Referensi lengkap

πŸ‹οΈ FINAL PROJECT β€” Hari 30
Buat laporan bisnis lengkap yang menjawab semua ini:

1.  Dashboard: total pesanan, revenue, avg order value
2.  Top 5 pelanggan VIP (nama, kota, total belanja, jumlah order)
3.  Top 5 produk terlaris (nama, kategori, terjual, revenue)
4.  Pertumbuhan penjualan bulan ke bulan (MoM growth %)
5.  Segmentasi pelanggan: VIP / Premium / Regular / Inactive
6.  Kategori mana kontribusi revenue paling besar (+ persentase)?
7.  Produk yang perlu restock (stok rendah, penjualan tinggi)
8.  Produk sering dibeli bersamaan (cross-sell opportunity)
9.  Rata-rata berapa hari dari daftar sampai pembelian pertama?
10. Executive summary: semua metrik kunci dalam 1 query
πŸ“‹ SQL Cheat Sheet Lengkap
Referensi cepat β€” simpan & gunakan kapan saja
Urutan Penulisan
SELECT    kolom
FROM      tabel
JOIN      gabung tabel
WHERE     filter baris
GROUP BY  kelompokkan
HAVING    filter grup
ORDER BY  urutkan
LIMIT     batasi jumlah
Urutan Eksekusi
FROM β†’ JOIN β†’ WHERE
β†’ GROUP BY β†’ HAVING
β†’ SELECT β†’ DISTINCT
β†’ ORDER BY β†’ LIMIT

Tips: WHERE tak bisa
pakai alias dari SELECT
Operator
=  !=  >  <  >=  <=
AND  OR  NOT  IN
BETWEEN x AND y
IS NULL / IS NOT NULL
LIKE 'A%'  LIKE '%x%'
% = karakter apapun
_ = tepat 1 karakter
Agregat
COUNT(*)   Hitung baris
COUNT(c)   Skip NULL
SUM(c)     Jumlahkan
AVG(c)     Rata-rata
MIN(c)     Terkecil
MAX(c)     Terbesar
JOIN
INNER JOIN  Cocok di kedua
LEFT JOIN   Semua kiri
SELF JOIN   Tabel←dirinya
CROSS JOIN  Semua kombinasi
Window Functions
ROW_NUMBER()  Nomor urut
RANK()        Ranking
DENSE_RANK()  Ranking padat
LAG()/LEAD()  Sebelum/sesudah
SUM() OVER()  Running total
NTILE(n)      Bagi n grup
DML
INSERT INTO t(c) VALUES(v)
UPDATE t SET c=v WHERE ...
DELETE FROM t WHERE ...

⚠️ SELALU pakai WHERE!
DDL & Lainnya
CREATE TABLE t (...)
ALTER TABLE ADD COLUMN
DROP TABLE IF EXISTS
CREATE VIEW v AS SELECT
CREATE INDEX i ON t(c)
WITH cte AS (...) SELECT
🎯 Tips Sukses Belajar SQL 30 Hari
1
Ketik sendiri β€” jangan copy-paste. Muscle memory sangat membantu.
2
Eksperimen β€” ubah query, lihat apa yang berubah.
3
Baca error β€” DBeaver kasih tahu letak kesalahan.
4
Konsisten 2-3 jam/hari β€” lebih baik dari 12 jam sekali.
5
Buat project nyata β€” database untuk kasus kerjamu sendiri.
6
Review tiap minggu β€” ulang materi sebelumnya secara berkala.
SQL Mastery β€” 30 Hari dari Nol Sampai Expert
Dibuat oleh Miftah, 2026.