[SERI RPL #Bagian 4/7 โข Level Menengah]
Pendahuluan: Pentingnya Perancangan Basis Data Terstruktur dalam Software Engineering
Dalam dunia rekayasa perangkat lunak (RPL), performa sebuah aplikasi sangat bergantung pada struktur penyimpanan datanya. Banyak pengembang pemula terjebak membuat satu tabel raksasa yang menampung seluruh informasi transaksi, pelanggan, hingga detail produk. Pendekatan monolitik ini menimbulkan bahaya laten seperti anomali pembaharuan (update anomaly), anomali penyisipan (insert anomaly), dan anomali penghapusan (delete anomaly), serta pemborosan memori server.
Melalui perancangan basis data rpl yang benar, kita memecah struktur data acak menjadi entitas-entitas logis terpisah yang saling terhubung menggunakan relasi Primary Key (PK) dan Foreign Key (FK). Artikel ini dirancang khusus sebagai panduan komprehensif bagi siswa SMK RPL, mahasiswa, maupun praktisi developer untuk menguasai tahapan normalisasi database dari 1NF, 2NF, hingga 3NF, disusul dengan implementasi Data Definition Language (DDL), Data Manipulation Language (DML), serta query SQL kompleks pada engine MySQL/MariaDB.
Konsep Utama Normalisasi Database: Dari 1NF hingga 3NF
Normalisasi adalah proses sistematis untuk mengorganisasi kolom dan tabel dalam database relasional. Tujuan utamanya adalah memastikan bahwa setiap data non-kunci (non-key attribute) hanya bergantung secara penuh pada Primary Key.
| Tingkat Normalisasi | Syarat Utama Struktur | Masalah yang Dieliminasi | Dampak pada Struktur Tabel |
|---|---|---|---|
| 1NF (First Normal Form) | Setiap kolom harus bernilai atomik (tunggal) dan tidak ada repeating group (kelompok berulang). | Nilai multivalue dalam satu sel (misal: daftar barang dipisah koma). | Baris bertambah, setiap sel berisi satu nilai tepat. |
| 2NF (Second Normal Form) | Memenuhi 1NF dan seluruh atribut non-primary key harus bergantung penuh pada Primary Key (Full Functional Dependency). | Partial Dependency (ketergantungan parsial pada composite primary key). | Tabel dipecah menjadi entitas induk dan entitas detail. |
| 3NF (Third Normal Form) | Memenuhi 2NF dan tidak ada ketergantungan transitif (atribut non-key bergantung pada atribut non-key lain). | Transitive Dependency (ketergantungan antar kolom non-primary key). | Membuat tabel referensi/master terpisah (misal: tabel wilayah, kategori). |
Studi Kasus Praktis: Normalisasi Tabel Transaksi Penjualan Retail
Bayangkan Anda menerima lembar kerja (spreadsheet) pesanan produk mentah dari sistem kasir lama berikut:
Data Unnormalized (UNF):
No_Nota: N-001 | Tgl: 2026-03-01 | Pelanggan: Budi (Jakarta) | Barang: [B-01: Laptop (1×10000000), B-02: Mouse (2×150000)]
- Langkah 1 (Transformasi ke 1NF): Hilangkan array/list barang. Pastikan setiap baris hanya berisi 1 nilai item barang tunggal. Primary Key komposit dibentuk oleh
(no_nota, kode_barang). - Langkah 2 (Transformasi ke 2NF): Pisahkan atribut yang hanya bergantung pada sebagian PK. Nama barang dan harga barang hanya bergantung pada
kode_barang(bukanno_nota). Maka buat tabeltbl_barangterpisah. - Langkah 3 (Transformasi ke 3NF): Amati atribut
alamat_pelangganyang bergantung padanama_pelanggan(bukan langsung pada PKno_nota). Pisahkan entitas pelanggan ke dalamtbl_pelanggantersendiri.
Implementasi DDL DML MySQL: Struktur Tabel dan Query Kompleks
Setelah proses normalisasi selesai, mari kita terjemahkan rancangan tersebut ke dalam bahasa SQL menggunakan MySQL/MariaDB secara hands-on.
1. Membuat Database dan Tabel (DDL)
-- 1. Buat Database
CREATE DATABASE IF NOT EXISTS db_tokoonline_rpl;
USE db_tokoonline_rpl;
-- 2. Tabel Master Pelanggan (3NF)
CREATE TABLE tbl_pelanggan (
id_pelanggan INT AUTO_INCREMENT PRIMARY KEY,
nama_pelanggan VARCHAR(100) NOT NULL,
kota VARCHAR(50) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
-- 3. Tabel Master Barang (2NF)
CREATE TABLE tbl_barang (
kode_barang VARCHAR(10) PRIMARY KEY,
nama_barang VARCHAR(100) NOT NULL,
harga_satuan DECIMAL(12,2) NOT NULL
) ENGINE=InnoDB;
-- 4. Tabel Transaksi / Header Nota
CREATE TABLE tbl_transaksi (
no_nota VARCHAR(15) PRIMARY KEY,
tgl_transaksi DATE NOT NULL,
id_pelanggan INT NOT NULL,
CONSTRAINT fk_transaksi_pelanggan
FOREIGN KEY (id_pelanggan) REFERENCES tbl_pelanggan(id_pelanggan)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB;
-- 5. Tabel Detail Transaksi (Pivot / Relasi Many-to-Many)
CREATE TABLE tbl_detail_transaksi (
no_nota VARCHAR(15) NOT NULL,
kode_barang VARCHAR(10) NOT NULL,
jumlah INT NOT NULL,
subtotal DECIMAL(12,2) NOT NULL,
PRIMARY KEY (no_nota, kode_barang),
CONSTRAINT fk_detail_nota FOREIGN KEY (no_nota) REFERENCES tbl_transaksi(no_nota) ON DELETE CASCADE,
CONSTRAINT fk_detail_barang FOREIGN KEY (kode_barang) REFERENCES tbl_barang(kode_barang) ON DELETE CASCADE
) ENGINE=InnoDB;
2. Pengisian Data Sampel (DML)
-- Insert Data Pelanggan & Barang
INSERT INTO tbl_pelanggan (nama_pelanggan, kota) VALUES
('Budi Santoso', 'Jakarta'),
('Siti Aminah', 'Bandung'),
('Eko Prasetyo', 'Surabaya');
INSERT INTO tbl_barang (kode_barang, nama_barang, harga_satuan) VALUES
('BRG-01', 'Laptop Asus Core i5', 8500000.00),
('BRG-02', 'Mouse Wireless Logistics', 150000.00),
('BRG-03', 'Keyboard Mechanical RGB', 450000.00);
-- Insert Data Transaksi
INSERT INTO tbl_transaksi (no_nota, tgl_transaksi, id_pelanggan) VALUES
('NT-2026001', '2026-03-01', 1),
('NT-2026002', '2026-03-02', 2),
('NT-2026003', '2026-03-02', 1);
-- Insert Detail Transaksi
INSERT INTO tbl_detail_transaksi (no_nota, kode_barang, jumlah, subtotal) VALUES
('NT-2026001', 'BRG-01', 1, 8500000.00),
('NT-2026001', 'BRG-02', 2, 300000.00),
('NT-2026002', 'BRG-03', 1, 450000.00),
('NT-2026003', 'BRG-02', 5, 750000.00);
3. Eksplorasi Query SQL Kompleks (JOIN, Aggregate, Subquery, HAVING)
Berikut adalah query relasional kompleks untuk menghasilkan laporan bisnis nyata:
-- Laporan Rekapitulasi Total Belanja per Pelanggan dengan Multi-JOIN dan HAVING
SELECT
p.id_pelanggan,
p.nama_pelanggan,
p.kota,
COUNT(DISTINCT t.no_nota) AS total_transaksi,
COALESCE(SUM(dt.subtotal), 0) AS grand_total_belanja
FROM tbl_pelanggan p
LEFT JOIN tbl_transaksi t ON p.id_pelanggan = t.id_pelanggan
LEFT JOIN tbl_detail_transaksi dt ON t.no_nota = dt.no_nota
GROUP BY p.id_pelanggan, p.nama_pelanggan, p.kota
HAVING grand_total_belanja > 400000
ORDER BY grand_total_belanja DESC;
ON DELETE CASCADE dan pengindeksan (indexing) pada Foreign Key akan sangat melatih kepekaan arsitektur database skala industri modern.Tanya Jawab Seputar desain database relasional normalisasi sql (FAQ)
Kapan kita harus menghentikan normalisasi? Apakah harus selalu sampai 5NF?
Dalam praktik industri umum dan pengembangan aplikasi web/mobile, normalisasi hingga tingkat 3NF (Third Normal Form) atau BCNF sudah sangat cukup untuk menjadwalkan efisiensi data tanpa merusak performa. Normalisasi di atas 3NF (seperti 4NF atau 5NF) sering kali menyebabkan jumlah tabel terlalu banyak (over-normalization) yang memicu perambatan waktu eksekusi akibat terlalu banyak operasi JOIN SQL.
Apa perbedaan mendasar antara INNER JOIN, LEFT JOIN, dan RIGHT JOIN?
INNER JOIN hanya menampilkan baris data yang memiliki kecocokan di kedua tabel. LEFT JOIN menampilkan seluruh baris data dari tabel sebelah kiri beserta data yang cocok dari tabel kanan (jika tidak cocok, bernilai NULL). Sedangkan RIGHT JOIN menampilkan seluruh data dari tabel kanan dan data matching dari tabel kiri.
Mengapa kita harus menggunakan klausa HAVING, bukan WHERE, saat menyaring aggregate function?
Klausa WHERE digunakan untuk memfilter baris individual sebelum proses pengelompokan (GROUP BY) dilakukan. Sedangkan klausa HAVING digunakan khusus untuk memfilter hasil pengelompokan dan fungsi agregasi seperti SUM(), COUNT(), atau AVG().

![Panduan Desain Database Relasional MySQL: Normalisasi 1NF-3NF dan Query SQL Kompleks [Seri RPL #4]](https://www.edusoe.my.id/wp-content/uploads/2026/10/blog_featured_1793163642-1024x538.jpg)