Reference · Database · SQL Server

SQL dasar: JOIN, WHERE vs HAVING, CTE, ROW_NUMBER, constraint

Ringkasan satu halaman. Dari Lesson 0019. Skrip lab: dotnet/lab/0019-sql-dasar.sql.

Urutan logis SELECT [1]

FROM → ON → JOIN → WHERE → GROUP BY → HAVING → SELECT → DISTINCT → ORDER BY → TOP

JOIN [2]

JOINHasil
INNER (default)hanya pasangan cocok; baris tanpa pasangan dibuang
LEFTsemua baris kiri; kolom kanan NULL bila tak ada pasangan
RIGHTsemua baris kanan (= LEFT dengan tabel dibalik)
FULL / CROSSsemua baris dua sisi / semua kombinasi
-- anti-join: Category tanpa Product
SELECT c.Name FROM dbo.Category c
LEFT JOIN dbo.Product p ON p.CategoryId = c.Id
WHERE p.Id IS NULL;

GROUP BY, WHERE vs HAVING [4]

SELECT c.Name, COUNT(*) AS InStockCount
FROM dbo.Product p JOIN dbo.Category c ON c.Id = p.CategoryId
WHERE p.Stock > 0             -- baris, sebelum grouping
GROUP BY c.Name
HAVING COUNT(*) >= 1000       -- grup, setelah agregasi
ORDER BY InStockCount DESC;   -- GROUP BY tidak mengurutkan

Subquery vs CTE [5] [6]

Top-N per grup [7]

WITH Ranked AS (
    SELECT c.Name AS CategoryName, p.Name, p.Price,
           ROW_NUMBER() OVER (PARTITION BY p.CategoryId ORDER BY p.Price DESC, p.Id) AS rn
    FROM dbo.Product p JOIN dbo.Category c ON c.Id = p.CategoryId
)
SELECT CategoryName, Name, Price, rn FROM Ranked
WHERE rn <= 3 ORDER BY CategoryName, rn;
FungsiNilai seri (contoh)Pakai bila
ROW_NUMBER1, 2, 3, 4tepat N baris; tambahkan pemecah seri (Id) supaya deterministik
RANK1, 2, 2, 4yang seri ikut, peringkat melompat
DENSE_RANK1, 2, 2, 3yang seri ikut, peringkat tidak melompat

Normalisasi, constraint, view

ConstraintAturan ProductIndex
PRIMARY KEY [9]Id unik, NOT NULL, satu per tabelunique index; clustered bila belum ada clustered index
FOREIGN KEY [9]CategoryId harus ada di Categorytidak otomatis (lesson 0022)
UNIQUE [10]nama Product unikunique non-clustered index
CHECK [10]Price > 0, Stock ≥ 0—; NULL lolos (UNKNOWN) → kolom NOT NULL

Jawaban 60–90 detik

CTE dengan ROW_NUMBER() OVER (PARTITION BY CategoryId ORDER BY Price DESC, Id): nomor mulai dari 1 per Category, Id sebagai pemecah seri. JOIN ke Category untuk nama. Filter rn <= 3 di query luar karena WHERE diproses sebelum window function. Harga seri harus ikut → DENSE_RANK/RANK. Aturan Product dijaga juga oleh UNIQUE/CHECK/FK karena engine menegakkannya untuk semua klien dan menutup race condition; Service tetap memvalidasi untuk pesan error.

Sumber: [1] SELECT: logical processing order · [2] FROM clause plus JOIN · [3] Joins · [4] SELECT - GROUP BY · [5] Subqueries · [6] WITH common_table_expression · [7] ROW_NUMBER · [8] Database normalization basics · [9] Primary and foreign key constraints · [10] Unique and check constraints · [11] Views