Mengubah dan Merancang · Pelajaran 8 dari 9
Merancang tabel dan normalisasi
10 menit baca · BelajarCode
Rancangan tabel yang buruk menyebabkan masalah yang sulit diperbaiki belakangan. Perhatikan catatan penjualan warung yang disimpan dalam satu tabel besar:
| no_nota | tanggal | pelanggan | telepon | produk | harga | jumlah |
|---|---|---|---|---|---|---|
| 1 | 2026-09-01 | Bu Sari | 0812000111 | Kopi susu, Roti bakar | 15000, 18000 | 2, 1 |
| 2 | 2026-09-01 | Pak Budi | 0813000222 | Kopi susu | 15000 | 3 |
| 3 | 2026-09-02 | Bu Sari | 0812000999 | Teh tarik | 12000 | 1 |
Masalahnya:
- Banyak nilai dalam satu sel: "Kopi susu, Roti bakar" sulit dicari dan dihitung.
- Data ganda: nama dan telepon Bu Sari disalin di setiap nota. Nomor teleponnya bahkan sudah tidak konsisten.
- Anomali perubahan: jika harga kopi susu naik, banyak baris harus diubah, dan mudah ada yang terlewat.
- Anomali penghapusan: menghapus satu-satunya nota Pak Budi juga menghapus data Pak Budi.
Normalisasi
Normalisasi memecah tabel supaya setiap fakta disimpan di satu tempat.
| Bentuk | Syarat sederhana |
|---|---|
| 1NF | Setiap sel berisi satu nilai, tidak ada daftar dalam satu sel |
| 2NF | 1NF, dan setiap kolom bergantung pada seluruh kunci, bukan sebagian |
| 3NF | 2NF, dan tidak ada kolom yang bergantung pada kolom bukan kunci lainnya |
Hasil normalisasi catatan warung:
1CREATE TABLE pelanggan (id INTEGER PRIMARY KEY, nama TEXT, telepon TEXT);2CREATE TABLE produk (id INTEGER PRIMARY KEY, nama TEXT, harga INTEGER);3CREATE TABLE nota (id INTEGER PRIMARY KEY, tanggal TEXT, pelanggan_id INTEGER REFERENCES pelanggan(id));4CREATE TABLE detail_nota (5 nota_id INTEGER REFERENCES nota(id),6 produk_id INTEGER REFERENCES produk(id),7 jumlah INTEGER,8 harga_saat_beli INTEGER,9 PRIMARY KEY (nota_id, produk_id)10);1112INSERT INTO pelanggan VALUES (1, 'Bu Sari', '0812000999'), (2, 'Pak Budi', '0813000222');13INSERT INTO produk VALUES (1, 'Kopi susu', 15000), (2, 'Roti bakar', 18000), (3, 'Teh tarik', 12000);14INSERT INTO nota VALUES (1, '2026-09-01', 1), (2, '2026-09-01', 2), (3, '2026-09-02', 1);15INSERT INTO detail_nota VALUES16 (1, 1, 2, 15000), (1, 2, 1, 18000),17 (2, 1, 3, 15000),18 (3, 3, 1, 12000);1920SELECT n.id AS nota, p.nama AS pelanggan, SUM(d.jumlah * d.harga_saat_beli) AS total21FROM nota n22JOIN pelanggan p ON p.id = n.pelanggan_id23JOIN detail_nota d ON d.nota_id = n.id24GROUP BY n.id, p.nama25ORDER BY n.id;nota | pelanggan | total 1 | Bu Sari | 48000 2 | Pak Budi | 45000 3 | Bu Sari | 12000
- Data pelanggan cukup disimpan sekali. Mengganti nomor telepon Bu Sari hanya mengubah satu baris.
detail_notaadalah tabel penghubung nota dan produk dengan kunci gabungan (nota_id, produk_id).harga_saat_belisengaja disimpan, karena harga produk bisa berubah. Nota lama tetap harus mencatat harga saat transaksi terjadi. Ini contoh keputusan rancangan yang disengaja, bukan data ganda.
Indeks
Indeks mempercepat pencarian pada kolom tertentu, mirip indeks di bagian belakang buku. Tanpa indeks, DBMS memeriksa seluruh baris. Dengan indeks (biasanya berbentuk B-tree), pencarian menjadi logaritmik.
1CREATE INDEX idx_nota_tanggal ON nota(tanggal);23SELECT id, tanggal FROM nota WHERE tanggal = '2026-09-01';id | tanggal 1 | 2026-09-01 2 | 2026-09-01
Indeks juga punya biaya: memakan ruang dan memperlambat INSERT dan UPDATE, karena indeks ikut diperbarui. Buat indeks untuk kolom yang sering dipakai di WHERE, JOIN, dan ORDER BY.
Cek pemahaman
Kenapa menyimpan nama dan telepon pelanggan di setiap baris penjualan dianggap rancangan yang buruk?
Latihan
Normalisasi data kursus
Tabel berikut menyimpan pendaftaran kursus: (nama_siswa, email_siswa, judul_kursus, nama_pengajar, tanggal_daftar). Satu siswa bisa mendaftar banyak kursus, dan satu pengajar bisa mengajar banyak kursus. Pecah menjadi tabel-tabel yang ternormalisasi.
Pembahasan
1CREATE TABLE siswa (id INTEGER PRIMARY KEY, nama TEXT, email TEXT UNIQUE);2CREATE TABLE pengajar (id INTEGER PRIMARY KEY, nama TEXT);3CREATE TABLE kursus (id INTEGER PRIMARY KEY, judul TEXT, pengajar_id INTEGER REFERENCES pengajar(id));4CREATE TABLE pendaftaran (5 siswa_id INTEGER REFERENCES siswa(id),6 kursus_id INTEGER REFERENCES kursus(id),7 tanggal_daftar TEXT,8 PRIMARY KEY (siswa_id, kursus_id)9);- Data siswa dan pengajar masing-masing disimpan sekali.
- Pengajar bergantung pada kursus, bukan pada pendaftaran, sehingga
pengajar_iddisimpan di tabel kursus (menghindari ketergantungan transitif, syarat 3NF). pendaftaranmenghubungkan siswa dan kursus (banyak ke banyak), dan tanggal daftar adalah fakta milik pasangan itu.