Aplikasi berkembang, dan tabel yang dulu dirancang sempurna perlahan jadi sempit: kolom telepon belum ada, nama kota terasa menyesatkan setelah maknanya berubah, dan kolom percobaan tinggal mengotori skema. SQLite menyediakan ALTER TABLE untuk perubahan struktur tanpa membongkar data — tetapi hanya untuk empat jenis operasi: menambah kolom, mengganti nama kolom, mengganti nama tabel, dan menghapus kolom. Chapter ini membedah keempatnya beserta batasannya, lalu menutup dengan pola klasik untuk perubahan yang lebih radikal.
Menambah Kolom dengan ADD COLUMN #
Kita pakai kembali tabel pelanggan dengan dua baris data:
sqlite> CREATE TABLE pelanggan (
...> id INTEGER PRIMARY KEY,
...> nama TEXT NOT NULL,
...> kota TEXT
...> );
sqlite> INSERT INTO pelanggan (nama, kota) VALUES ('Budi', 'Jakarta'), ('Siti', 'Bandung');
sqlite> ALTER TABLE pelanggan ADD COLUMN telepon TEXT;
sqlite> SELECT * FROM pelanggan;
1|Budi|Jakarta|
2|Siti|Bandung|
sqlite> ALTER TABLE pelanggan ADD COLUMN poin INTEGER DEFAULT 0;
sqlite> SELECT * FROM pelanggan;
1|Budi|Jakarta||0
2|Siti|Bandung||0
sqlite>Kolom baru selalu menempel di urutan paling akhir — ALTER TABLE tidak bisa menyisipkan kolom di tengah. ADD COLUMN tanpa DEFAULT mengisi baris lama dengan NULL; dengan DEFAULT 0 seperti kolom poin, semua baris lama langsung bernilai 0.
Tidak semua definisi kolom diterima. Tiga penolakan berikut paling umum:
sqlite> ALTER TABLE pelanggan ADD COLUMN email TEXT UNIQUE;
Parse error: Cannot add a UNIQUE column
sqlite> ALTER TABLE pelanggan ADD COLUMN dibuat TEXT DEFAULT CURRENT_TIMESTAMP;
Runtime error: Cannot add a column with non-constant default
sqlite> ALTER TABLE pelanggan ADD COLUMN umur INTEGER NOT NULL;
Runtime error: Cannot add a NOT NULL column with default value NULL
sqlite>Alur berpikirnya satu: ADD COLUMN harus bisa mengisi baris-baris lama seketika. UNIQUE ditolak karena dua baris lama dengan nilai sama akan melanggar; CURRENT_TIMESTAMP dan ekspresi lain ditolak karena nilainya tidak tetap; NOT NULL tanpa default ditolak karena tidak ada nilai untuk baris lama. Konstanta sederhana seperti 0 atau '-' selalu aman.
Mengganti Nama #
Dua operasi ganti nama dimiliki SQLite: nama kolom dan nama tabel:
sqlite> ALTER TABLE pelanggan RENAME COLUMN kota TO kota_asal;
sqlite> ALTER TABLE pelanggan RENAME TO pelanggan_lama;
sqlite> SELECT id, nama, kota_asal FROM pelanggan_lama;
1|Budi|Jakarta
2|Siti|Bandung
sqlite>Operasi RENAME COLUMN menulis ulang skema lalu memeriksa ulang seluruhnya, sehingga view, trigger, dan foreign key yang merujuk kolom tersebut ikut diperbarui otomatis. RENAME TO mengubah identitas tabelnya sendiri — setelah operasi ini, statement yang menyebut nama lama akan ditolak dengan error no such table.
Menghapus Kolom dengan DROP COLUMN #
DROP COLUMN — tersedia sejak SQLite 3.35.0 — membuang kolom beserta isinya dari tabel:
sqlite> ALTER TABLE pelanggan_lama DROP COLUMN telepon;
sqlite> SELECT * FROM pelanggan_lama;
1|Budi|Jakarta|0
2|Siti|Bandung|0
sqlite> ALTER TABLE pelanggan_lama DROP COLUMN id;
Parse error: cannot drop PRIMARY KEY column: "id"
sqlite>Kolom telepon lenyap beserta isinya — ALTER TABLE tidak mengenal UNDO, jadi kolom yang sudah dijatuhkan hanya bisa dipulihkan dari backup. Penolakan kedua terjadi karena kolom id adalah PRIMARY KEY — jati diri baris — dan engine menolak melepasnya. Penolakan serupa berlaku untuk kolom dengan UNIQUE, kolom yang menjadi rujukan indeks, kolom yang disebut dalam CHECK level tabel, serta kolom yang dirujuk foreign key.
DROP TABLE #
Menghapus tabel berarti membuang struktur dan seluruh isinya sekaligus:
sqlite> DROP TABLE pelanggan_lama;
sqlite> DROP TABLE pelanggan_lama;
Parse error: no such table: pelanggan_lama
sqlite> DROP TABLE IF EXISTS pelanggan_lama;
sqlite>Penghapusan kedua gagal karena tabelnya memang sudah lenyap sejak penghapusan pertama. Sama seperti CREATE TABLE IF NOT EXISTS, bentuk DROP TABLE IF EXISTS membuat statement aman untuk skrip yang dijalankan berulang: tabelnya tidak ada, statement dilewati tanpa error.
Perubahan Radikal: Pola 12 Langkah #
Empat operasi di atas adalah semua yang dimiliki ALTER TABLE. Mengubah tipe kolom, menata ulang urutan kolom, atau menambah primary key pada tabel yang sudah berisi data — semuanya tidak didukung langsung. Untuk kebutuhan seperti itu, dokumentasi sqlite.org merumuskan prosedur yang dikenal sebagai pola 12 langkah; intinya:
- Matikan sementara pemeriksaan foreign key:
PRAGMA foreign_keys=OFF. - Buka transaksi dengan
BEGIN. - Simpan definisi indeks, trigger, dan view yang menempel pada tabel lama.
- Buat tabel baru dengan struktur yang diinginkan, dengan nama sementara.
- Salin data:
INSERT INTO tabel_baru SELECT ... FROM tabel_lama. DROP TABLEtabel lama.- Ganti nama tabel baru menjadi nama lama:
ALTER TABLE tabel_baru RENAME TO tabel_lama. - Bangun ulang indeks, trigger, dan view yang tersimpan pada langkah 3.
- Periksa kesehatan foreign key dengan
PRAGMA foreign_key_check. - Tutup transaksi dengan
COMMIT, lalu nyalakan kembaliPRAGMA foreign_keys=ON.
Seluruh proses berjalan dalam satu transaksi: jika langkah mana pun gagal, ROLLBACK mengembalikan keadaan tabel lama. Kunci keamanannya ada pada urutan langkah 4–7: bangun tabel baru dengan nama sementara, salin datanya, baru ganti nama — kebalikannya (mengganti nama tabel lama lebih dulu) berisiko merusak rujukan trigger dan view yang masih menunjuk nama tersebut.
Skema, data, dan perintah dasar untuk mengelolanya kini lengkap kita kuasai. Section Query Lanjutan melangkah lebih jauh: menggabungkan tabel dengan JOIN, meringkas dengan agregasi, dan menyusun query bertingkat.