Relasi Antar Tabel: Primary Key, Foreign Key, dan Cara Berpikir Database
Memahami mengapa data dipecah ke banyak tabel, jenis relasi (satu-ke-banyak, banyak-ke-banyak), dan membuat FOREIGN KEY dengan aturan ON DELETE.
Kenapa tidak taruh semua di satu tabel besar?
Bayangkan tabel pesanan yang menyimpan nama pelanggan, kota, dan alamat di setiap baris:
| no | pelanggan | kota | produk |
|---|---|---|---|
| 1 | Budi Santoso | Jakarta | Kopi |
| 2 | Budi Santoso | Jakarta | Roti |
| 3 | Budi Santoso | Jakarta | Teh |
Budi pindah ke Bandung? Kamu harus mengubah semua barisnya; satu terlewat, datanya jadi bertentangan. Ditulis "Budi Santoso" di satu baris dan "Budi S." di baris lain? Laporan jadi kacau. Solusinya: pecah menjadi tabel-tabel kecil yang saling menunjuk.
Kunci utama dan kunci tamu
- Primary Key (PK) — pengenal unik tiap baris sebuah tabel. Contoh:
pelanggan.id. - Foreign Key (FK) — kolom di tabel lain yang menunjuk ke PK. Contoh:
pesanan.pelanggan_idmenunjukpelanggan.id.
Analogi KTP: daftar pesanan tidak menulis ulang seluruh biodata Budi; cukup mencatat "nomor KTP-nya" (pelanggan_id = 1). Biodata lengkapnya disimpan sekali di tabel pelanggan. Ubah di satu tempat, berlaku di mana-mana.
Tiga jenis relasi
| Jenis | Artinya | Contoh | Cara membuatnya |
|---|---|---|---|
| Satu-ke-banyak (1:N) | Satu baris A punya banyak baris B | 1 pelanggan → banyak pesanan | FK di tabel "banyak" (pesanan.pelanggan_id) |
| Banyak-ke-banyak (N:M) | A punya banyak B dan sebaliknya | pesanan ↔ produk (satu pesanan banyak produk, satu produk di banyak pesanan) | Tabel penghubung (detail_pesanan) berisi dua FK |
| Satu-ke-satu (1:1) | Satu baris A punya tepat satu B | pengguna ↔ profil lengkap | FK yang juga UNIQUE |
Perhatikan tabel detail_pesanan di KopiKita: ia adalah jembatan antara pesanan dan produk, dan juga menyimpan jumlah yang hanya masuk akal untuk pasangan pesanan-produk tertentu.
Membuat FOREIGN KEY
CREATE TABLE penulis (
id INT AUTO_INCREMENT PRIMARY KEY,
nama VARCHAR(80) NOT NULL
);
CREATE TABLE buku (
id INT AUTO_INCREMENT PRIMARY KEY,
judul VARCHAR(150) NOT NULL,
penulis_id INT NOT NULL,
FOREIGN KEY (penulis_id) REFERENCES penulis(id)
);
Urutan penting: tabel yang ditunjuk (penulis) harus dibuat duluan. Saat menghapus, kebalikannya: hapus tabel anak dulu.
Apa yang dijaga FK?
INSERT INTO buku (judul, penulis_id) VALUES ('Laskar Pelangi', 99);
-- ERROR: Cannot add or update a child row: a foreign key constraint fails
-- (tidak ada penulis dengan id 99)
Dengan FK, tidak mungkin ada "buku yatim" yang menunjuk penulis yang tidak ada. Database menjaga integritas referensial.
Aturan saat induk dihapus/diubah
FOREIGN KEY (penulis_id) REFERENCES penulis(id)
ON DELETE CASCADE -- penulis dihapus → bukunya ikut terhapus
-- ON DELETE SET NULL -- bukunya tetap, penulis_id menjadi NULL
-- ON DELETE RESTRICT -- (bawaan) tolak penghapusan selama masih ada buku
ON UPDATE CASCADE
CASCADE berbahaya jika asal dipakai: menghapus satu pelanggan bisa menghapus seluruh riwayat pesanannya secara diam-diam. Untuk data keuangan, lebih aman RESTRICT + soft delete.
Syarat di MySQL asli: mesin tabel harus InnoDB (bawaan sejak MySQL 5.5) dan tipe kolom FK harus sama dengan kolom yang ditunjuk (INT dengan INT).