Empat episode terakhir kita belajar mengoperasikan database: CRUD di #64, filter di #65, JOIN di #66. Tapi ada satu pertanyaan yang belum dijawab: siapa yang menentukan tabel-tabel itu ada? Kenapa tabel pelanggan dipisah dari pesanan? Kenapa tidak satu tabel raksasa saja?
Jawabannya adalah desain database, dan episode ini menutup seri Database dan SQL kita. Ini adalah keterampilan yang membedakan programmer yang "bisa query" dengan programmer yang "bisa merancang sistem". Query bisa dipelajari dalam seminggu, tapi desain yang buruk akan menghantuimu berbulan-bulan lewat bug dan migrasi yang menyakitkan.
Analoginya seperti membangun rumah. Tukang yang langsung menumpuk bata tanpa denah mungkin cepat di awal, tapi begitu pemilik minta tambah kamar, semuanya harus dibongkar. Desain database adalah denah rumah datamu: entitas apa saja yang ada, bagaimana mereka berhubungan, dan aturan apa yang menjaga kerapian. Di akhir artikel ini kamu akan bisa merancang database sederhana dari nol untuk aplikasi web versimu sendiri.
Mulai dari Kebutuhan, Bukan dari Tabel
Kesalahan paling umum: langsung membuka phpMyAdmin dan membuat tabel. Padahal langkah pertama desain justru tidak menyentuh database sama sekali. Mulailah dari kebutuhan aplikasinya.
Ambil contoh aplikasi kantin online sederhana. Fiturnya: pelanggan mendaftar, melihat daftar menu, memesan beberapa menu sekaligus, dan melihat riwayat pesanannya. Dari deskripsi itu, lingkari kata bendanya: pelanggan, menu, pesanan. Tiga kata benda itu adalah calon tabelmu, yang dalam istilah database disebut entitas.
Langkah berikutnya, daftarkan atribut tiap entitas, yaitu data apa yang perlu disimpan:
- pelanggan: nama, email, nomor HP, alamat
- menu: nama, harga, kategori, deskripsi
- pesanan: tanggal pesan, total bayar, status
Baru setelah daftar ini jelas, kamu boleh berpikir tentang tabel. Desain yang baik selalu berangkat dari "data apa yang dibutuhkan aplikasi", bukan "tabel apa yang keren dibuat".
Tentukan Primary Key Tiap Tabel
Setiap tabel wajib punya primary key: kolom yang nilainya unik untuk tiap baris, tidak boleh kosong, dan tidak boleh berubah. Fungsinya seperti nomor KTP: cara database menunjuk "baris yang itu, bukan yang lain" tanpa keraguan.
Untuk pemula, aturan praktisnya sederhana: tambahkan kolom id bertipe INT AUTO_INCREMENT sebagai primary key di hampir semua tabel. Kenapa tidak pakai kolom alami seperti email atau nomor HP? Karena data alami bisa berubah (orang ganti email) dan bisa duplikat dalam kasus aneh. Kolom id buatan tidak pernah berubah dan dijamin unik oleh database. Ini bukan kemalasan, ini keputusan desain yang disengaja: primary key yang stabil membuat semua relasi di bawahnya ikut stabil.
Relasi One-to-Many: Satu Induk, Banyak Anak
Sekarang hubungkan entitasnya. Satu pelanggan bisa membuat banyak pesanan, tapi satu pesanan hanya milik satu pelanggan. Ini disebut relasi one-to-many (satu ke banyak), relasi paling umum di aplikasi web.
Caranya: taruh foreign key di sisi "banyak". Tabel pesanan mendapat kolom pelanggan_id yang merujuk ke pelanggan.id:
CREATE TABLE pelanggan (
id INT AUTO_INCREMENT PRIMARY KEY,
nama VARCHAR(100) NOT NULL,
email VARCHAR(100) NOT NULL UNIQUE
);
CREATE TABLE pesanan (
id INT AUTO_INCREMENT PRIMARY KEY,
pelanggan_id INT NOT NULL,
tanggal DATE NOT NULL,
total INT NOT NULL,
status VARCHAR(20) DEFAULT 'baru',
FOREIGN KEY (pelanggan_id) REFERENCES pelanggan(id)
);
Foreign key bukan sekadar dokumentasi, ia adalah aturan yang ditegakkan database. Kamu tidak bisa memasukkan pesanan dengan pelanggan_id 999 kalau pelanggan 999 tidak ada. Database menolaknya. Inilah yang disebut referential integrity: database ikut menjaga datamu tetap waras, bukan cuma aplikasimu.
Relasi Many-to-Many Butuh Tabel Penghubung
Satu pesanan bisa berisi banyak menu, dan satu menu bisa muncul di banyak pesanan. Ini relasi many-to-many (banyak ke banyak), dan ia tidak bisa diwakili satu foreign key saja. Mau ditaruh di sisi mana pun, satu kolom tidak cukup menampung banyak nilai.
Solusinya: buat tabel penghubung (junction table) yang memecah relasi many-to-many menjadi dua relasi one-to-many:
CREATE TABLE detail_pesanan (
pesanan_id INT NOT NULL,
menu_id INT NOT NULL,
jumlah INT NOT NULL DEFAULT 1,
PRIMARY KEY (pesanan_id, menu_id),
FOREIGN KEY (pesanan_id) REFERENCES pesanan(id),
FOREIGN KEY (menu_id) REFERENCES menu(id)
);
Tabel ini berisi dua foreign key sekaligus. Primary key-nya gabungan kedua kolom, supaya pasangan yang sama tidak tercatat dua kali. Kolom jumlah adalah bonus: data yang hanya bermakna dalam konteks hubungan itu ("pesanan ini memesan 2 porsi menu itu") memang tempatnya di tabel penghubung.
Berhenti dan tebak dulu! Aplikasi perpustakaan punya entitas anggota dan buku. Satu anggota bisa meminjam banyak buku, satu buku bisa dipinjam banyak anggota (di waktu berbeda). Relasi apa ini, dan tabel apa yang dibutuhkan?
Rapikan dengan Normalisasi
Normalisasi adalah seni memecah tabel yang berantakan menjadi tabel-tabel yang rapi, supaya tidak ada data yang disimpan berulang-ulang. Kamu tidak perlu menghafal semua bentuk normalnya, cukup pahami tiga yang pertama dengan contoh nyata.
Bayangkan tabel serampangan ini:
-- tabel pesanan_berantakan
-- id | pelanggan_nama | menu_dipesan
-- 1 | Budi | Nasi Goreng, Es Teh
-- 2 | Siti | Mie Goreng
1NF (bentuk normal pertama): tiap sel hanya boleh berisi satu nilai, tidak boleh daftar. Kolom menu_dipesan berisi "Nasi Goreng, Es Teh" sekaligus, itu pelanggaran. Akibatnya kamu tidak bisa mencari "siapa saja yang memesan Es Teh" dengan query normal.
Berhenti dan tebak dulu! Kenapa menyimpan daftar menu sebagai teks "Nasi Goreng, Es Teh" dalam satu kolom adalah ide buruk? Sebutkan minimal dua masalahnya.
2NF: semua kolom non-kunci harus bergantung pada seluruh primary key, bukan sebagian. 3NF: kolom non-kunci tidak boleh bergantung pada kolom non-kunci lain (misalnya menyimpan kota sekaligus provinsi di tabel pelanggan, padahal provinsi bisa diturunkan dari kota, lebih baik tabel kota terpisah).
Untuk kebanyakan aplikasi web, berhenti di 3NF sudah sangat cukup. Dan ini meluruskan mitos pertama: "semakin banyak tabel semakin bagus". Normalisasi berlebihan (over-normalization) membuat query butuh JOIN berkali-kali dan jadi lambat. Desain yang baik itu seimbang: cukup rapi untuk menjaga konsistensi, cukup sederhana untuk dibaca dan di-query.
Mitos kedua: "desain bisa dipikir belakangan, yang penting jalan dulu". Menambah kolom itu murah, tapi mengubah relasi di tengah jalan itu mahal: data lama harus dimigrasi, query lama harus ditulis ulang, dan aplikasi harus berhenti sejenak. Satu jam mendesain di awal menghemat berhari-hari perombakan di kemudian hari.
Kuis Cepat
Kuis cepat: Di aplikasi kantin online, satu menu bisa ada di banyak pesanan dan satu pesanan berisi banyak menu. Desain yang tepat?
Latihan Penutup Seri: Desain Kantin Online Versimu
Ini proyek mini penutup seri Database dan SQL. Di kertas atau aplikasi catatan, rancang database untuk aplikasi pemesanan kantin versimu sendiri:
- Tuliskan 3-4 entitas dari kebutuhan aplikasimu (contoh: pelanggan, menu, pesanan, kurir).
- Untuk tiap entitas, daftarkan atributnya dan tentukan primary key-nya.
- Gambarkan relasinya: mana yang one-to-many, mana yang many-to-many. Untuk yang many-to-many, buat tabel penghubungnya dan beri nama yang jelas.
- Tulis CREATE TABLE untuk semuanya, lengkap dengan foreign key.
- Uji desainmu: tulis 3 query: (a) daftar pesanan beserta nama pelanggannya (JOIN), (b) 5 menu termurah (ORDER BY + LIMIT), (c) pelanggan yang belum pernah memesan (LEFT JOIN + IS NULL). Kalau ketiganya bisa ditulis dengan wajar, desainmu lolos.
Selamat, kamu menutup seri Database dan SQL: dari konsep relasional (#63), CRUD (#64), filter (#65), JOIN (#66), sampai desain (#67). Fondasi datamu sudah kokoh. Di episode #68 kita masuk wilayah baru yang seru: Kenalan dengan CodeIgniter 4 dan Cara Installnya, framework PHP pertama di perjalanan backend-mu. Semua ilmu SQL dari seri ini akan langsung terpakai di sana.
Diskusi & Komentar 0
Punya tanggapan, pertanyaan, atau tips seputar tutorial ini? Tulis komentar kamu di bawah!
Jadilah yang pertama membuka obrolan dan berbagi pandangan seputar tutorial resep kode ini.
Tulis Komentar
Komentar menggunakan akun Google. Harap berkomentar dengan santun dan berbobot.