Kebutuhan aplikasi hampir tidak pernah berhenti di desain pertama: pelanggan minta kolom email, aturan bisnis menuntut poin tidak boleh negatif, nama kolom kota ternyata harus kota_domisili supaya tidak ambigu. Menghapus tabel lama lalu membuat yang baru bukan pilihan — datanya ikut musnah. Untuk itu PostgreSQL menyediakan ALTER TABLE: satu keluarga perintah untuk mengubah tabel yang sudah berisi data tanpa mengosongkannya. Pada chapter ini kita membedah varian-variannya satu per satu — menambah kolom, mengganti tipe, mengatur default, memasang constraint, mengganti nama, dan menghapus kolom — semuanya di atas tabel yang sama yang terus berisi data.

Menyiapkan Tabel Latihan #

Tabel pelanggan berikut sengaja dibuat dengan kekurangan yang akan kita perbaiki sepanjang chapter — kolom email belum ada, kodepos keliru bertipe teks, dan kolom kota belum punya nilai default:

sql buat-tabel.sql
CREATE TABLE pelanggan (
    id      integer PRIMARY KEY,
    nama    text NOT NULL,
    telepon text,
    kodepos text,
    kota    text
);

INSERT INTO pelanggan (id, nama, telepon, kodepos, kota)
VALUES
    (1, 'Budi', '081234567890', '10110', 'Jakarta'),
    (2, 'Siti', '081298765432', '40115', 'Bandung');

SELECT id, nama, telepon, kodepos, kota
FROM pelanggan
ORDER BY id;

Output yang Dihasilkan:

text
CREATE TABLE
INSERT 0 2
 id | nama |   telepon    | kodepos |  kota   
----+------+--------------+---------+---------
  1 | Budi | 081234567890 | 10110   | Jakarta
  2 | Siti | 081298765432 | 40115   | Bandung
(2 rows)

Perhatikan dua hal dari data awal: kodepos berisi teks ('10110' dengan kutip), dan setiap perubahan kita akan diverifikasi dengan SELECT — data Budi dan Siti harus tetap utuh sampai akhir chapter.

Menambah Kolom #

Bentuk termudah ALTER TABLE: ADD COLUMN nama_kolom tipe_data. Kolom baru ditambahkan di posisi paling akhir, dan baris-baris lama mendapat nilai NULL — kecuali kolom itu punya DEFAULT, yang langsung mengisi baris lama sekaligus:

ALTER TABLE pelanggan ADD COLUMN email text;

ALTER TABLE pelanggan ADD COLUMN poin integer DEFAULT 0;

SELECT id, nama, email, poin
FROM pelanggan
ORDER BY id;

Output yang Dihasilkan:

text
ALTER TABLE
ALTER TABLE
 id | nama | email | poin 
----+------+-------+------
  1 | Budi |       |    0
  2 | Siti |       |    0
(2 rows)

Bedah singkatnya: ADD COLUMN email text menambah kolom kosong — kedua baris lama menampilkan NULL karena belum ada emailnya; ADD COLUMN poin integer DEFAULT 0 menambah kolom ber-default — PostgreSQL sejak versi 11 mengisi baris lama dengan nilai default secara cepat (defaultnya dicatat sebagai aturan, data tidak ditulis ulang fisik), sehingga Budi dan Siti langsung punya poin = 0 tanpa tabel tersentuh lama. Tidak ada data yang hilang pada kedua operasi.

Mengubah Tipe Kolom #

ALTER COLUMN ... TYPE mengganti tipe kolom yang sudah terlanjur terisi. Konversi yang memperluas (misalnya integer ke numeric) dijalankan otomatis, tetapi konversi yang cara bacanya berbeda — seperti teks ke angka — harus kita ajari dengan klausa USING berisi ekspresi konversinya:

sql ubah-tipe.sql
ALTER TABLE pelanggan
    ALTER COLUMN kodepos TYPE integer USING kodepos::integer;

SELECT id, nama, kodepos
FROM pelanggan
ORDER BY id;

Output yang Dihasilkan:

text
ALTER TABLE
 id | nama | kodepos 
----+------+---------
  1 | Budi |   10110
  2 | Siti |   40115
(2 rows)

Operator ::integer mengubah teks '10110' menjadi angka 10110 untuk setiap baris — terlihat dari hasil SELECT di mana kodepos kini tampil sebagai angka (rata kanan, tanpa kutip). Tanpa klausa USING, PostgreSQL menolak perintah ini karena tidak tahu cara mengubah teks menjadi angka secara implisit. Klausa ini juga tempat menulis konversi khusus, misalnya USING kodepos::integer bisa diganti USING NULLIF(kodepos, '')::integer bila kolom lama berisi string kosong yang harus dibaca sebagai NULL.

Mengatur Nilai Default #

Default kolom bisa dipasang kapan saja — termasuk setelah tabel berisi data. SET DEFAULT hanya mengatur aturan untuk baris baru; nilai baris lama tidak tersentuh:

ALTER TABLE pelanggan
    ALTER COLUMN kota SET DEFAULT 'Jakarta';

INSERT INTO pelanggan (id, nama, telepon, kodepos)
VALUES (3, 'Andi', '081277788899', '60233');

SELECT id, nama, kota
FROM pelanggan
ORDER BY id;

Output yang Dihasilkan:

text
ALTER TABLE
INSERT 0 1
 id | nama |  kota   
----+------+---------
  1 | Budi | Jakarta
  2 | Siti | Bandung
  3 | Andi | Jakarta
(3 rows)

INSERT untuk Andi sengaja tidak menyebut kolom kota, dan hasilnya baris Andi menerima 'Jakarta' dari default yang barusan dipasang. Padanan SET DEFAULT tersedia juga: DROP DEFAULT melepas aturan itu kembali.

Menambah Constraint Setelah Tabel Berjalan #

Constraint tidak harus ada sejak tabel dicipta. ADD CONSTRAINT memasangnya belakangan — dengan satu syarat penting: data yang sudah ada harus lolos pemeriksaannya, karena server memeriksa seluruh isi tabel saat memasang constraint:

ALTER TABLE pelanggan
    ADD CONSTRAINT poin_tidak_negatif CHECK (poin >= 0);

\d pelanggan

Output yang Dihasilkan:

text
ALTER TABLE
                  Table "public.pelanggan"
 Column  |  Type   | Collation | Nullable |     Default     
---------+---------+-----------+----------+-----------------
 id      | integer |           | not null | 
 nama    | text    |           | not null | 
 telepon | text    |           |          | 
 kodepos | integer |           |          | 
 kota    | text    |           |          | 'Jakarta'::text
 email   | text    |           |          | 
 poin    | integer |           |          | 0
Indexes:
    "pelanggan_pkey" PRIMARY KEY, btree (id)
Check constraints:
    "poin_tidak_negatif" CHECK (poin >= 0)

Bagian Check constraints: pada hasil \d memperlihatkan constraint baru bernama poin_tidak_negatif dengan syaratnya. Mulai sekarang, INSERT atau UPDATE yang mencoba memberi nilai poin negatif akan ditolak dengan error. Memberi nama eksplisit seperti poin_tidak_negatif — alih-alih membiarkan server mengarang nama seperti pelanggan_poin_check — membuat error di kemudian hari jauh lebih mudah dibaca.

Mengganti Nama dan Menghapus Kolom #

Dua penyesuaian terakhir kita: memperjelas nama kolom dan membuang kolom yang sudah tidak dipakai. RENAME COLUMN mengubah nama tanpa menyentuh data; DROP COLUMN membuang kolom beserta isinya:

ALTER TABLE pelanggan RENAME COLUMN kota TO kota_domisili;

ALTER TABLE pelanggan DROP COLUMN telepon;

\d pelanggan

Output yang Dihasilkan:

text
ALTER TABLE
ALTER TABLE
                     Table "public.pelanggan"
    Column     |  Type   | Collation | Nullable |     Default     
---------------+---------+-----------+----------+-----------------
 id            | integer |           | not null | 
 nama          | text    |           | not null | 
 kodepos       | integer |           |          | 
 kota_domisili | text    |           |          | 'Jakarta'::text
 email         | text    |           |          | 
 poin          | integer |           |          | 0
Indexes:
    "pelanggan_pkey" PRIMARY KEY, btree (id)
Check constraints:
    "poin_tidak_negatif" CHECK (poin >= 0)

Hasil \d memperlihatkan bentuk akhir tabel: kolom kota kini bernama kota_domisili, kolom telepon hilang, dan sisanya utuh — termasuk constraint poin_tidak_negatif yang tetap terpasang. Perubahan nama seperti ini juga tersedia untuk tabel itu sendiri: ALTER TABLE pelanggan RENAME TO pelanggan_toko mengganti nama tabel tanpa mengubah isinya.

Satu catatan terakhir: seluruh contoh chapter ini mengubah tabel secara permanen — tidak ada tombol undo untuk ALTER TABLE yang sudah terlanjur. Kebiasaan profesional sederhana: jalankan SELECT dulu untuk memastikan data aman, ubah sedikit-sedikit, dan verifikasi dengan \d setiap langkah.

Struktur bisa dibangun dan dibentuk ulang — bagian terakhir dari siklus ini adalah membongkarnya dengan aman: menghapus tabel dan database yang memang sudah tidak dibutuhkan. Itulah topik chapter Menghapus Database dan Tabel.

Referensi #

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

atur-default.sql

Unduh berkas
sql
ALTER TABLE pelanggan
    ALTER COLUMN kota SET DEFAULT 'Jakarta';

INSERT INTO pelanggan (id, nama, telepon, kodepos)
VALUES (3, 'Andi', '081277788899', '60233');

SELECT id, nama, kota
FROM pelanggan
ORDER BY id;

buat-tabel.sql

Unduh berkas
sql
CREATE TABLE pelanggan (
    id      integer PRIMARY KEY,
    nama    text NOT NULL,
    telepon text,
    kodepos text,
    kota    text
);

INSERT INTO pelanggan (id, nama, telepon, kodepos, kota)
VALUES
    (1, 'Budi', '081234567890', '10110', 'Jakarta'),
    (2, 'Siti', '081298765432', '40115', 'Bandung');

SELECT id, nama, telepon, kodepos, kota
FROM pelanggan
ORDER BY id;

ganti-nama-hapus.sql

Unduh berkas
sql
ALTER TABLE pelanggan RENAME COLUMN kota TO kota_domisili;

ALTER TABLE pelanggan DROP COLUMN telepon;

\d pelanggan

tambah-constraint.sql

Unduh berkas
sql
ALTER TABLE pelanggan
    ADD CONSTRAINT poin_tidak_negatif CHECK (poin >= 0);

\d pelanggan

tambah-kolom.sql

Unduh berkas
sql
ALTER TABLE pelanggan ADD COLUMN email text;

ALTER TABLE pelanggan ADD COLUMN poin integer DEFAULT 0;

SELECT id, nama, email, poin
FROM pelanggan
ORDER BY id;

ubah-tipe.sql

Unduh berkas
sql
ALTER TABLE pelanggan
    ALTER COLUMN kodepos TYPE integer USING kodepos::integer;

SELECT id, nama, kodepos
FROM pelanggan
ORDER BY id;