Pada Section Dasar SQL kita sudah menulis CREATE TABLE pertama dan mengenal beberapa tipe kolom dasar. Chapter ini menaikkan kegiatannya dari sekadar menulis sintaks menjadi aktivitas perancangan: sebelum mengetik SQL, kita memutuskan terlebih dahulu data apa yang perlu disimpan, tipe apa yang paling tepat, dan kolom mana yang wajib terisi. Kita akan mempraktikkan alur tersebut dengan merancang tabel barang untuk sebuah toko alat tulis, menuliskannya sebagai statement CREATE TABLE yang bersih, lalu memverifikasi hasil rancangannya melalui DESC. Kebiasaan merancang sebelum menulis ini akan kita pakai di sepanjang Section Table Design, mulai dari primary key hingga ALTER TABLE.

Merancang Kolom Sebelum Menulis SQL #

Tabel yang bermasalah hampir selalu bermula dari rancangan yang tergesa: kolom ditambah asal-asalan setelah aplikasi berjalan, tipe dipilih asal jalan, dan kolom wajib tidak pernah dipikirkan. Perbaikan struktur di kemudian hari jauh lebih mahal daripada lima menit berpikir di awal, karena data yang sudah tersimpan harus ikut disesuaikan. Oleh sebab itu kita selalu mulai dari pertanyaan rancangan berikut:

  • Data apa yang benar-benar perlu disimpan? Setiap kolom harus menjawab kebutuhan nyata, bukan “siapa tahu nanti berguna”.
  • Nilainya berbentuk apa? Angka, teks, tanggal, atau nilai biner — bentuk nilai menentukan tipe kolom.
  • Berapa ukuran maksimalnya? Nama barang jarang lebih dari 100 karakter; nomor telepon tidak lebih dari 20.
  • Apakah kolom ini wajib terisi? Kolom yang wajib diberi NOT NULL; kolom opsional dibiarkan mengizinkan NULL.

Untuk tabel barang di toko alat tulis, hasil jawaban atas keempat pertanyaan tersebut kita rangkum menjadi satu tabel rancangan kecil:

KolomTipeWajib terisiAlasan singkat
idINTyanomor identifikasi barang saat diskusi atau laporan
namaVARCHAR(100)yasetiap barang pasti bernama
kategoriVARCHAR(50)yadasar pengelompokan barang
hargaDECIMAL(10,2)yanilai uang menuntut presisi tetap
stokINTyajumlah fisik di gudang
pemasokVARCHAR(100)tidakbarang baru bisa saja belum diketahui pemasoknya
tanggal_masukDATEyajejak kapan barang mulai tercatat

Kolom harga sengaja memakai DECIMAL(10,2), bukan FLOAT, karena tipe DECIMAL menyimpan angka secara persis — penting untuk perhitungan kasir dan pajak. Kolom pemasok kita biarkan opsional sebagai contoh kolom yang memang sah bernilai NULL.

Konvensi Penamaan snake_case #

Nama tabel dan kolom akan ditulis ratusan kali di query, laporan, dan kode aplikasi, sehingga formatnya perlu konsisten sejak awal. Konvensi yang paling umum di dunia SQL adalah snake_case: huruf kecil semua, kata dipisah garis bawah, tanpa spasi. Perbandingannya terlihat seperti berikut:

Gaya penamaanContohPenilaian
snake_casetanggal_masukkonsisten dan mudah diketik — standar kita
camelCasetanggalMasuksah, tetapi jarang dipakai untuk kolom SQL
PascalCaseTanggalMasukrawan salah kapital di query
Ber-spasitanggal masukmemaksa nama dikutip terus-menerus

MySQL memang mengizinkan nama ber-spasi selama ditulis dalam tanda kutip ganda atau backtick, tetapi praktik tersebut hanya mengundang kesalahan penulisan. Nama tabel memakai bentuk tunggal (barang, pelanggan) atau jamak (produk) sama-sama lazim — pilih satu dan pertahankan di seluruh database.

Kita mulai dengan menyiapkan database latihan khusus chapter ini, lalu menuliskan hasil rancangan sebagai CREATE TABLE:

sql
CREATE DATABASE belajar_desain;
USE belajar_desain;

Output yang Dihasilkan:

text
Query OK, 1 row affected (0.00 sec)

Database changed
sql
CREATE TABLE barang (
  id INT NOT NULL,
  nama VARCHAR(100) NOT NULL,
  kategori VARCHAR(50) NOT NULL,
  harga DECIMAL(10,2) NOT NULL,
  stok INT NOT NULL,
  pemasok VARCHAR(100),
  tanggal_masuk DATE NOT NULL
);

Output yang Dihasilkan:

text
Query OK, 0 rows affected (0.00 sec)

Respons Query OK, 0 rows affected menandakan struktur berhasil dibuat — 0 rows karena statement ini mendefinisikan struktur, bukan mengisi baris data. Mari kita bedah setiap barisnya:

  1. Baris 1 (CREATE TABLE barang (): Keyword CREATE TABLE diikuti nama tabel barang; tanda kurung buka membuka daftar definisi kolom.
  2. Baris 2 (id INT NOT NULL): Kolom id bertipe bilangan bulat. Klausa NOT NULL mewajibkan kolom ini terisi pada setiap baris.
  3. Baris 3 (nama VARCHAR(100) NOT NULL): Kolom nama barang bertipe string maksimal 100 karakter, juga wajib terisi.
  4. Baris 4 (kategori VARCHAR(50) NOT NULL): Nama kategori barang, string maksimal 50 karakter, wajib terisi.
  5. Baris 5 (harga DECIMAL(10,2) NOT NULL): Harga dengan total 10 digit, 2 di antaranya di belakang koma — cukup untuk barang sampai 99.999.999,99.
  6. Baris 6 (stok INT NOT NULL): Jumlah stok berupa bilangan bulat, wajib terisi.
  7. Baris 7 (pemasok VARCHAR(100)): Tanpa NOT NULL, kolom ini opsional — baris barang baru boleh menyimpan NULL.
  8. Baris 8 (tanggal_masuk DATE NOT NULL): Tanggal pencatatan format YYYY-MM-DD, wajib terisi, menutup daftar tanpa koma.

Perhatikan pola yang konsisten: setiap definisi kolom berbentuk nama — tipe — aturan. Statement ini memang belum memasang kunci utama; kita sengaja menundanya karena primary key punya chapter tersendiri yang membahasnya tuntas.

Mengisi Data dan Melihat Hasilnya #

Struktur baru terasa nyata begitu berisi data. Dua baris berikut meniru barang yang datang bersamaan dari pemasok CV Menara:

sql
INSERT INTO barang (id, nama, kategori, harga, stok, pemasok, tanggal_masuk) VALUES
  (1, 'Buku Tulis 58', 'Alat Tulis', 4500.00, 120, 'CV Menara', '2026-01-10'),
  (2, 'Pensil Kayu 2B', 'Alat Tulis', 2500.00, 300, 'CV Menara', '2026-01-10');

Output yang Dihasilkan:

text
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0
sql
SELECT id, nama, kategori, harga, stok, pemasok, tanggal_masuk
FROM barang
ORDER BY id;

Output yang Dihasilkan:

text
+----+----------------+------------+---------+------+-----------+---------------+
| id | nama           | kategori   | harga   | stok | pemasok   | tanggal_masuk |
+----+----------------+------------+---------+------+-----------+---------------+
|  1 | Buku Tulis 58  | Alat Tulis | 4500.00 |  120 | CV Menara | 2026-01-10    |
|  2 | Pensil Kayu 2B | Alat Tulis | 2500.00 |  300 | CV Menara | 2026-01-10    |
+----+----------------+------------+---------+------+-----------+---------------+
2 rows in set (0.00 sec)

Kolom pada INSERT kita sebut satu per satu alih-alih memakai VALUES tanpa daftar kolom, karena urutan kolom di struktur bisa berubah saat tabel berkembang. Pada SELECT kita menambahkan ORDER BY id supaya urutan hasil selalu sama — kebiasaan yang membuat output query dapat diprediksi.

Membaca Struktur dengan DESC #

Setelah tabel dibuat, kita bisa membuka kembali rancangannya kapan saja tanpa membuka file SQL-nya. Perintah DESC (singkatan dari DESCRIBE) menampilkan struktur tabel saat ini:

sql
DESC barang;

Output yang Dihasilkan:

text
+---------------+---------------+------+-----+---------+-------+
| Field         | Type          | Null | Key | Default | Extra |
+---------------+---------------+------+-----+---------+-------+
| id            | int           | NO   |     | NULL    |       |
| nama          | varchar(100)  | NO   |     | NULL    |       |
| kategori      | varchar(50)   | NO   |     | NULL    |       |
| harga         | decimal(10,2) | NO   |     | NULL    |       |
| stok          | int           | NO   |     | NULL    |       |
| pemasok       | varchar(100)  | YES  |     | NULL    |       |
| tanggal_masuk | date          | NO   |     | NULL    |       |
+---------------+---------------+------+-----+---------+-------+
7 rows in set (0.00 sec)

Enam kolom pada hasil DESC masing-masing membawa informasi rancangan:

KolomMaknanya
Fieldnama kolom sesuai yang kita tulis di CREATE TABLE
Typetipe data hasil akhir, termasuk panjangnya
NullNO bila kolom wajib terisi, YES bila boleh NULL
Keystatus kunci — masih kosong karena belum ada primary key
Defaultnilai bawaan kolom — NULL berarti tidak ada nilai bawaan
Extraatribut tambahan seperti auto_increment

Kolom Key yang kosong pada seluruh baris menegaskan bahwa tabel barang kita belum punya kunci utama — tidak ada mekanisme yang mencegah dua baris dengan id sama. Itulah celah yang akan ditutup oleh chapter berikutnya tentang PRIMARY KEY.

Terakhir, kita bereskan database latihan chapter ini supaya lingkungan belajar tetap bersih:

sql
DROP DATABASE IF EXISTS belajar_desain;

Output yang Dihasilkan:

text
Query OK, 1 row affected (0.00 sec)

Angka 1 row affected pada respons DROP DATABASE bukan jumlah baris data, melainkan jumlah tabel yang ikut dibuang — di sini satu tabel barang beserta isinya.

Referensi #

Tabel barang kini berdiri dengan kolom yang dipilih secara sadar — tipe sesuai bentuk nilai dan status wajib sesuai kebutuhan bisnis. Struktur ini masih menerima baris dengan id kembar, dan itulah pekerjaan yang diambil alih oleh PRIMARY KEY pada chapter berikutnya.