Menyimpan daftar pelanggan di file teks atau spreadsheet memang bisa, tetapi pendekatan tersebut cepat berantakan ketika data bertambah banyak, harus dicari dengan cepat, atau diubah oleh beberapa orang sekaligus. Model relational database menyelesaikan masalah tersebut dengan mengorganisasi data menjadi kumpulan table kecil yang saling terhubung melalui kunci. MySQL adalah implementasi dari model tersebut. Pada Chapter ini kita akan membedah anatomi table, memahami primary key dan foreign key, lalu membangun dua table yang saling berelasi sebagai latihan pertama.
Anatomi Table: Baris dan Kolom #
Table adalah struktur data paling dasar dalam database relasional; bentuknya berupa kisi dua dimensi yang mirip spreadsheet. Satu kolom mewakili satu atribut data dan memiliki tipe data yang tetap, sedangkan satu baris mewakili satu entitas data yang utuh. Sebagai contoh, table pelanggan bisa berbentuk seperti ini:
| id | nama | kota |
|---|---|---|
| 1 | Budi | Bandung |
| 2 | Siti | Jakarta |
| 3 | Anton | Surabaya |
Kolom id bertipe bilangan bulat, sedangkan kolom nama dan kota bertipe teks. Satu baris berisi data satu pelanggan secara lengkap, sehingga table di atas menyimpan tiga pelanggan.
Walau tampilannya mirip, table database berbeda dari spreadsheet dalam tiga hal penting. Pertama, tipe data setiap kolom ditegakkan secara ketat oleh server — kolom bertipe bilangan bulat akan menolak teks. Kedua, jumlah dan jenis kolom bersifat tetap; menambah atribut berarti mengubah struktur table secara eksplisit. Ketiga, table dapat menampung jutaan baris dan tetap dicari dengan cepat melalui index.
Primary Key dan Foreign Key #
Primary key adalah kolom (atau gabungan kolom) yang nilainya unik untuk setiap baris dan tidak boleh kosong. Primary key berfungsi sebagai identitas resmi sebuah baris: pada table pelanggan, kolom id menjadi primary key sehingga tidak pernah ada dua pelanggan dengan id yang sama.
Foreign key adalah kolom yang nilainya merujuk primary key pada table lain. Kolom pelanggan_id di table pesanan boleh berisi angka 1 karena terdapat pelanggan dengan id 1; nilai seperti 99 akan ditolak server selama belum ada pelanggan bersangkutan. Melalui pasangan primary key dan foreign key inilah dua table membentuk relasi.
Relasi pada diagram di atas adalah one-to-many: satu pelanggan dapat memiliki banyak pesanan, tetapi satu pesanan hanya dimiliki oleh satu pelanggan. Satu pelanggan yang sama boleh muncul di banyak baris pesanan melalui pelanggan_id yang berulang. Pola satu-ke-banyak ini adalah relasi paling umum pada aplikasi nyata.
Mengapa Data Dipecah ke Beberapa Table #
Kita bisa saja menyimpan nama pelanggan langsung pada setiap baris pesanan. Cara tersebut membuat data mudah diduplikasi: nama pelanggan yang sama tertulis berkali-kali, dan ketika pelanggan pindah kota, kita harus mengubah banyak baris sekaligus — satu saja yang terlewat, data jadi tidak konsisten.
Dengan memecah data menjadi pelanggan dan pesanan, data pelanggan cukup disimpan satu kali di table pelanggan. Table pesanan hanya menyimpan rujukan pelanggan_id, sehingga perubahan data pelanggan berlangsung di satu tempat. Proses memecah data untuk menghilangkan duplikasi semacam ini disebut normalisasi dan akan kita dalami pada bagian desain database.
Praktik: Membangun Dua Table yang Berelasi #
Sekarang kita bangun contoh nyatanya di MySQL. Seluruh latihan berlangsung di database khusus bernama belajar_toko supaya tidak mengganggu database lain. Buat database-nya terlebih dahulu:
CREATE DATABASE belajar_toko;Output yang Dihasilkan:
Query OK, 1 row affected (0.00 sec)Selanjutnya kita membuat dua table. Perhatikan bahwa setiap perintah diakhiri titik koma (;) — penanda akhir statement bagi mysql client:
USE belajar_toko;
CREATE TABLE pelanggan (
id INT PRIMARY KEY,
nama VARCHAR(50),
kota VARCHAR(30)
);
CREATE TABLE pesanan (
id INT PRIMARY KEY,
pelanggan_id INT,
total DECIMAL(10,2),
FOREIGN KEY (pelanggan_id) REFERENCES pelanggan(id)
);Output yang Dihasilkan:
Database changed
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.00 sec)Mari kita bedah baris-baris penting pada perintah di atas:
USE belajar_toko;— menjadikanbelajar_tokosebagai database aktif untuk perintah-perintah berikutnya dalam sesi yang sama.id INT PRIMARY KEY— kolom bilangan bulat yang sekaligus menjadi primary key table.nama VARCHAR(50)— kolom teks dengan panjang maksimum 50 karakter.total DECIMAL(10,2)— angka presisi dengan total 10 digit dan 2 digit di belakang koma; tipe ini cocok untuk nilai uang.FOREIGN KEY (pelanggan_id) REFERENCES pelanggan(id)— mendeklarasikanpesanan.pelanggan_idsebagai rujukan kepelanggan.id, sehingga MySQL menolak pesanan yang menunjuk pelanggan yang tidak ada.
Table sudah siap; sekarang kita isi dengan data contoh:
USE belajar_toko;
INSERT INTO pelanggan (id, nama, kota) VALUES
(1, 'Budi', 'Bandung'),
(2, 'Siti', 'Jakarta'),
(3, 'Anton', 'Surabaya');
INSERT INTO pesanan (id, pelanggan_id, total) VALUES
(101, 1, 150000.00),
(102, 1, 75000.00),
(103, 2, 320000.00);Output yang Dihasilkan:
Database changed
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0Data di atas sengaja tidak merata: Budi memiliki dua pesanan, Siti satu pesanan, dan Anton belum memiliki pesanan sama sekali. Distribusi seperti ini justru bagus untuk menguji perilaku query berelasi. Sekarang kita gabungkan kedua table dengan JOIN:
USE belajar_toko;
SELECT pesanan.id, pelanggan.nama, pesanan.total
FROM pesanan
JOIN pelanggan ON pesanan.pelanggan_id = pelanggan.id
ORDER BY pesanan.id;Output yang Dihasilkan:
Database changed
+-----+------+-----------+
| id | nama | total |
+-----+------+-----------+
| 101 | Budi | 150000.00 |
| 102 | Budi | 75000.00 |
| 103 | Siti | 320000.00 |
+-----+------+-----------+
3 rows in set (0.00 sec)Query di atas bekerja dalam empat tahap. Klausa FROM pesanan menetapkan table utama, lalu JOIN pelanggan ON pesanan.pelanggan_id = pelanggan.id memasangkan setiap baris pesanan dengan baris pelanggan yang id-nya sama dengan pelanggan_id-nya. Daftar kolom setelah SELECT mengambil nilai dari kedua table yang sudah terpasangkan, dan ORDER BY pesanan.id menjaga urutan hasil tetap teratur.
Perhatikan bahwa Anton tidak muncul pada hasil. Query JOIN standar hanya menampilkan baris yang memiliki pasangan di kedua table; karena Anton belum punya pesanan, baris Anton tidak memiliki pasangan. Variasi LEFT JOIN yang mempertahankan baris tanpa pasangan akan kita bahas pada bagian joins.
Terakhir, kita bersihkan database latihan karena contoh ini sudah selesai dipakai:
DROP DATABASE belajar_toko;Output yang Dihasilkan:
Query OK, 2 rows affected (0.00 sec)Referensi #
- CREATE TABLE Statement — MySQL 8.4 Reference Manual
- FOREIGN KEY Constraints — MySQL 8.4 Reference Manual
- JOIN Clause — MySQL 8.4 Reference Manual
Table, baris, kolom, dan kunci adalah kosakata dasar model relasional yang baru saja kita praktikkan. Namun untuk berbicara dengan MySQL, kita membutuhkan bahasanya: SQL. Chapter berikutnya memetakan keluarga perintah SQL dan hubungannya dengan MySQL.