Semua tabel yang kita rancang sepanjang section ini dibuat sekali jadi — skenario ideal yang jarang bertahan lama. Kebutuhan bisnis berubah: laporan baru minta kolom ringkasan, kebijakan mutakhir menjadikan kolom opsional jadi wajib, dan kesalahan penamaan baru terlihat setelah aplikasi berjalan. ALTER TABLE adalah perintah untuk memperbaiki tabel yang sudah hidup tanpa membuang datanya. Pada chapter ini kita akan menambah, mengubah tipe, mengganti nama, dan menghapus kolom; me-rename tabel; memasang constraint setelah tabel berisi data; lalu mempelajari dua galat khas saat perubahan bentrok dengan data yang sudah tersimpan — beserta urutan langkah yang membuat migrasi skema tetap aman.
Menyiapkan Tabel Latihan #
Kita pakai tabel artikel sederhana yang sudah berisi dua baris:
CREATE DATABASE belajar_ubah;
USE belajar_ubah;Output yang Dihasilkan:
Query OK, 1 row affected (0.00 sec)
Database changedCREATE TABLE artikel (
id INT PRIMARY KEY,
judul VARCHAR(100) NOT NULL,
penulis VARCHAR(100)
);
INSERT INTO artikel (id, judul, penulis) VALUES
(1, 'Belajar Desain Tabel', 'Budi'),
(2, 'Tips Memilih Tipe Data', 'Ani');Output yang Dihasilkan:
Query OK, 0 rows affected (0.00 sec)
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0Menambah Kolom dengan ADD COLUMN #
Perubahan paling ringan adalah menambah kolom baru. Kolom baru tanpa NOT NULL dan tanpa default membuat baris lama terisi NULL — aman karena tidak ada data yang dipaksa berubah:
ALTER TABLE artikel ADD COLUMN ringkasan VARCHAR(255);Output yang Dihasilkan:
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0DESC artikel;Output yang Dihasilkan:
+-----------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+-------+
| id | int | NO | PRI | NULL | |
| judul | varchar(100) | NO | | NULL | |
| penulis | varchar(100) | YES | | NULL | |
| ringkasan | varchar(255) | YES | | NULL | |
+-----------+--------------+------+-----+---------+-------+
4 rows in set (0.00 sec)Kolom ringkasan kini hadir di posisi terakhir dengan nilai NULL pada kedua baris lama. Satu statement ALTER TABLE hanya perlu satu klausul perubahan; beberapa perubahan bisa digabung dengan koma, tetapi memisahkannya membuat tiap perubahan mudah diuji dan dibatalkan.
Mengubah Tipe dengan MODIFY COLUMN #
Klausa MODIFY COLUMN mengubah definisi kolom tanpa mengganti namanya. Memperlebar VARCHAR adalah arah yang aman — tidak ada data yang bisa terpotong:
ALTER TABLE artikel MODIFY COLUMN penulis VARCHAR(150);Output yang Dihasilkan:
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0Kapasitas penulis naik dari 100 menjadi 150 karakter. Perubahan yang lebih berbahaya adalah menambah NOT NULL pada kolom yang masih menyimpan NULL. Kita tambahkan dulu satu baris yang penulisnya kosong:
INSERT INTO artikel (id, judul, penulis, ringkasan) VALUES
(3, 'Jebakan Kolom Opsional', NULL, NULL);Output yang Dihasilkan:
Query OK, 1 row affected (0.00 sec)-- @error
ALTER TABLE artikel MODIFY COLUMN penulis VARCHAR(150) NOT NULL;Output yang Dihasilkan:
Query OK, 0 rows affected (0.00 sec)
ERROR 1138 (22004): Invalid use of NULL value
ByeServer menolak perubahan itu dengan galat ERROR 1138 (22004): Invalid use of NULL value — baris id 3 masih memuat NULL pada kolom yang ingin dijadikan wajib. Jalan keluarnya: isi dulu datanya, baru ubah strukturnya:
UPDATE artikel SET penulis = 'Tim Redaksi' WHERE id = 3;
ALTER TABLE artikel MODIFY COLUMN penulis VARCHAR(150) NOT NULL;
DESC artikel;Output yang Dihasilkan:
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
+-----------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+-------+
| id | int | NO | PRI | NULL | |
| judul | varchar(100) | NO | | NULL | |
| penulis | varchar(150) | NO | | NULL | |
| ringkasan | varchar(255) | YES | | NULL | |
+-----------+--------------+------+-----+---------+-------+
4 rows in set (0.00 sec)Setelah UPDATE mengisi penulis baris ketiga, MODIFY ke NOT NULL berhasil, dan DESC menunjukkan penulis kini varchar(150) dengan Null = NO. Perhatikan pula baris Rows matched: 1 Changed: 1 Warnings: 0 pada output UPDATE — satu baris cocok dengan kondisi WHERE dan satu baris benar-benar berubah nilainya. Inilah miniatur urutan aman migrasi skema: siapkan data dulu, ketatkan struktur belakangan.
Mengganti Nama dengan CHANGE COLUMN dan RENAME TO #
Klausa CHANGE COLUMN mengganti nama sekaligus definisi kolom — nama baru ditulis lebih dulu, definisinya menyusul:
ALTER TABLE artikel CHANGE COLUMN ringkasan sinopsis VARCHAR(255);
DESC artikel;Output yang Dihasilkan:
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
+----------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+-------+
| id | int | NO | PRI | NULL | |
| judul | varchar(100) | NO | | NULL | |
| penulis | varchar(150) | NO | | NULL | |
| sinopsis | varchar(255) | YES | | NULL | |
+----------+--------------+------+-----+---------+-------+
4 rows in set (0.00 sec)Kolom ringkasan berganti nama menjadi sinopsis dengan definisi yang sama. Nama tabel sendiri diganti lewat RENAME TO:
ALTER TABLE artikel RENAME TO tulisan;
SHOW TABLES;Output yang Dihasilkan:
Query OK, 0 rows affected (0.00 sec)
+------------------------+
| Tables_in_belajar_ubah |
+------------------------+
| tulisan |
+------------------------+
1 row in set (0.00 sec)Daftar tabel kini memuat tulisan. Perintah RENAME tidak menyentuh isi data maupun kolom — hanya identitas tabelnya yang berubah, sehingga seluruh query lama yang menyebut artikel harus diperbarui setelahnya.
Menghapus Kolom dengan DROP COLUMN #
Menghapus kolom bersifat permanen: datanya ikut lenyap dan tidak bisa dibatalkan dengan ALTER lain.
ALTER TABLE tulisan DROP COLUMN sinopsis;
DESC tulisan;Output yang Dihasilkan:
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
+---------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+--------------+------+-----+---------+-------+
| id | int | NO | PRI | NULL | |
| judul | varchar(100) | NO | | NULL | |
| penulis | varchar(150) | NO | | NULL | |
+---------+--------------+------+-----+---------+-------+
3 rows in set (0.00 sec)Struktur tulisan kembali ramping. Sebelum menghapus kolom produksi, pastikan tidak ada view, stored procedure, atau query aplikasi yang masih membacanya.
Memasang Constraint Setelah Tabel Berisi Data #
Constraint tidak harus hadir sejak CREATE TABLE. Kita tambahkan kolom slug dulu, lalu menegakkannya dengan ADD UNIQUE:
ALTER TABLE tulisan ADD COLUMN slug VARCHAR(100);
ALTER TABLE tulisan ADD UNIQUE slug_unik (slug);
DESC tulisan;Output yang Dihasilkan:
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
+---------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+--------------+------+-----+---------+-------+
| id | int | NO | PRI | NULL | |
| judul | varchar(100) | NO | | NULL | |
| penulis | varchar(150) | NO | | NULL | |
| slug | varchar(100) | YES | UNI | NULL | |
+---------+--------------+------+-----+---------+-------+
4 rows in set (0.00 sec)Kolom slug tampil dengan penanda UNI di kolom Key — constraint unik bernama slug_unik kini aktif meski dipasang belakangan. Penegakannya langsung terasa:
INSERT INTO tulisan (id, judul, penulis, slug) VALUES
(4, 'Kunci yang Tertukar', 'Siti', 'kunci-tertukar');Output yang Dihasilkan:
Query OK, 1 row affected (0.00 sec)-- @error
INSERT INTO tulisan (id, judul, penulis, slug) VALUES (5, 'Kunci Kembar', 'Budi', 'kunci-tertukar');Output yang Dihasilkan:
Query OK, 0 rows affected (0.00 sec)
ERROR 1062 (23000): Duplicate entry 'kunci-tertukar' for key 'tulisan.slug_unik'
ByeGalat 1062 menolak slug kembar — constraint baru bekerja persis seperti yang dipasang sejak awal. Pola yang sama berlaku untuk primary key dan foreign key. Dua contoh berikut memasangnya pada tabel yang baru dibuat tanpa kunci:
CREATE TABLE penanda (kode INT NOT NULL, label VARCHAR(50));
ALTER TABLE penanda ADD PRIMARY KEY (kode);
DESC penanda;Output yang Dihasilkan:
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| kode | int | NO | PRI | NULL | |
| label | varchar(50) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)CREATE TABLE penulis (
id INT PRIMARY KEY,
nama VARCHAR(100) NOT NULL
);
CREATE TABLE buku (
id INT PRIMARY KEY,
penulis_id INT,
judul VARCHAR(100) NOT NULL
);
ALTER TABLE buku ADD CONSTRAINT fk_buku_penulis
FOREIGN KEY (penulis_id) REFERENCES penulis (id);
INSERT INTO penulis (id, nama) VALUES (1, 'Budi');
INSERT INTO buku (id, penulis_id, judul) VALUES (1, 1, 'Belajar Desain Tabel');Output yang Dihasilkan:
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
Query OK, 1 row affected (0.00 sec)
Query OK, 1 row affected (0.00 sec)Syarat penambahan constraint belakangan tetap sama seperti saat pembuatan: data yang ada harus sudah mematuhi aturannya — ADD PRIMARY KEY gagal bila ada duplikat, dan ADD FOREIGN KEY gagal bila ada baris yatim.
Menyusutkan Kolom yang Berisi Data Panjang #
Arah berbahaya dari MODIFY adalah menyusutkan kapasitas. Kita buktikan pada tabel kecil:
CREATE TABLE pendek (
id INT PRIMARY KEY,
nama VARCHAR(50)
);
INSERT INTO pendek VALUES (1, 'Nama Kolom Yang Sangat Panjang Sekali');Output yang Dihasilkan:
Query OK, 0 rows affected (0.00 sec)
Query OK, 1 row affected (0.00 sec)-- @error
ALTER TABLE pendek MODIFY COLUMN nama VARCHAR(10);Output yang Dihasilkan:
Query OK, 0 rows affected (0.00 sec)
ERROR 1265 (01000): Data truncated for column 'nama' at row 1
ByePerubahan itu ditolak dengan galat ERROR 1265 (01000): Data truncated for column 'nama' at row 1 — memangkas kolom menjadi 10 karakter berarti memotong nilai sepanjang 37 karakter, dan mode ketat melarang pemotongan senyap. Bila penyusutan memang harus dilakukan, jalankan UPDATE yang memangkas nilainya terlebih dahulu, baru MODIFY kolomnya.
Urutan Aman Migrasi Skema #
Dua galat di atas (1138 dan 1265) mengajarkan pola yang sama: struktur baru hanya boleh ditegakkan setelah data siap. Urutan aman menambah kolom wajib pada tabel produksi:
- Tambah kolom sebagai opsional —
ADD COLUMNtanpaNOT NULL, sehingga baris lama terisiNULLdan aplikasi lama tetap berjalan. - Perbarui data yang kosong — isi baris lama lewat
UPDATEsampai tidak adaNULLyang tersisa. - Ketatkan strukturnya —
MODIFY COLUMN ... NOT NULLsetelah semua baris terisi. - Perbarui aplikasi — pastikan seluruh
INSERTbaru sudah mengirim kolom tersebut sebelum langkah 3, agar pengguna tidak menabrak galat1364.
Referensi #
- ALTER TABLE Statement — MySQL 8.4 Reference Manual
- CREATE TABLE Statement — MySQL 8.4 Reference Manual
- FOREIGN KEY Constraints — MySQL 8.4 Reference Manual
Tabel kini bisa tumbuh mengikuti kebutuhan: kolom ditambah dan diketatkan, nama diperbaiki, constraint dipasang belakangan — semuanya tanpa kehilangan data yang sudah terkumpul. Dengan ini pula perangkat desain tabel kita lengkap: dari merancang kolom pertama sampai memigrasikan struktur yang sudah dipakai. Section berikutnya melangkah ke lapisan data itu sendiri — cara menyisipkan, membaca, mengubah, dan menghapus isi tabel dengan DML. Sebelum itu, kita bereskan database latihan:
DROP DATABASE IF EXISTS belajar_ubah;Output yang Dihasilkan:
Query OK, 5 rows affected (0.00 sec)Lima tabel — tulisan, pendek, penanda, penulis, dan buku — ikut terbuang.