Episode ini membahas fondasi desain database relasional: Entity Relationship Diagram, Primary Key dan Foreign Key, prinsip normalisasi data dari 1NF hingga BCNF, serta praktik langsung Data Definition Language (DDL) untuk membuat, mengubah, dan menghapus database serta tabel.

Selamat datang di episode 2 series Belajar SQL PostgreSQL! Pada episode 1, kita sudah memahami sejarah model relasional dan alasan memilih PostgreSQL. Sekarang saatnya melompat ke fondasi teknis yang paling penting: bagaimana merancang database yang baik. Sebagian besar masalah database di dunia nyata — data duplikat, inkonsistensi, query yang melambat — sebenarnya lahir dari desain yang buruk, bukan dari engine yang salah.
Di episode ini, kita akan membahas pemodelan data relasional dengan Entity Relationship Diagram (ERD), peran Primary Key, Foreign Key, dan Unique Constraint, prinsip normalisasi data dari 1NF hingga BCNF, lalu praktik langsung Data Definition Language (DDL).
Sebelum menulis CREATE TABLE, seorang database designer yang baik menggambar dulu gambaran besarnya. Pemodelan data adalah proses mengubah kebutuhan bisnis dunia nyata menjadi struktur database yang bisa dieksekusi.
Entity Relationship Diagram (ERD) adalah diagram yang menggambarkan entitas, atribut, dan hubungan antar entitas. Dalam konteks database relasional:
users, products, orders.email, price, status.users 1 ────── n orders n ────── 1 products
(id) (id, user_id) (id)
(email) (product_id) (name)
(quantity) (price)Bacaan diagram di atas: satu users memiliki banyak orders, dan setiap orders merujuk ke satu products. Relasi semacam ini dikenal sebagai one-to-many, dan ini adalah pola paling umum dalam desain database relasional. Ada juga relasi one-to-one dan many-to-many yang biasanya dipecah menjadi tabel penghubung.
Tip
Aturan praktis: jika satu entity bisa memiliki banyak entity lain (misal satu user punya banyak order), maka entity "banyak" menyimpan foreign key ke entity "satu". Jadi tabel orders menyimpan user_id — bukan sebaliknya. Pola ini hampir selalu benar.
Tiga konsep ini adalah tulang punggung integritas database relasional:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email TEXT UNIQUE NOT NULL
);
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES users(id),
total NUMERIC(10,2) NOT NULL
);Perhatikan: kolom user_id di tabel orders adalah foreign key yang merujuk ke id di tabel users. Berkat FK ini, database akan menolak order dengan user_id yang tidak ada di tabel users — integritas terjaga otomatis oleh engine.
Normalisasi adalah proses merancang struktur tabel untuk meminimalkan duplikasi data dan mencegah anomali. Data yang diulang-ulang bukan hanya boros storage — ia adalah bom waktu inkonsistensi: kalau satu salinan diupdate tapi yang lain tidak, mana yang benar?
Normalisasi bekerja lewat tingkatan yang disebut Normal Form (NF). Semakin tinggi tingkatan, semakin bersih strukturnya:
| Normal Form | Aturan utama | Masalah yang dicegah |
|---|---|---|
| 1NF | Setiap kolom menyimpan nilai atomik; tidak ada array atau daftar terpisah koma | Kolom multi-nilai yang sulit diquery |
| 2NF | Memenuhi 1NF + semua non-key bergantung penuh pada primary key | Duplikasi data pada composite key |
| 3NF | Memenuhi 2NF + tidak ada ketergantungan transitif (non-key bergantung pada non-key lain) | Update anomaly pada data turunan |
| BCNF | Versi ketat 3NF: setiap determiner harus candidate key | Anomali sisa yang tak tertangkap 3NF |
Mari kita lihat contoh praktis. Tabel berikut melanggar 1NF karena kolom tags menyimpan banyak nilai dalam satu kolom:
CREATE TABLE products_bad (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
tags TEXT NOT NULL
);Perbaikan 1NF adalah memindahkan tags ke tabel terpisah yang menyimpan satu tag per baris. Demikian seterusnya: setiap tingkatan normalisasi menghilangkan satu kelas anomali data.
Penting untuk dicatat: normalisasi bukan dogma tanpa pengecualian. Di dunia nyata, tabel denormalisasi (sengaja menambahkan duplikasi) sering dilakukan untuk keperluan performa analitik — misalnya menyimpan kolom total_revenue yang diagregat, atau memakai JSONB untuk atribut fleksibel. Kita akan melihat kapan denormalisasi beralasan di episode 20 (studi kasus e-commerce).
Note
Aturan emasnya: normalisasi dulu sampai 3NF, lalu denormalisasi secara sadar dan terdokumentasi jika ada alasan performa yang kuat.
Setelah desain dan normalisasi matang, saatnya menuangkan ke SQL. Data Definition Language (DDL) adalah kumpulan perintah untuk mendefinisikan dan mengelola struktur database — database, tabel, kolom, dan constraint.
CREATE DATABASE shop;
DROP DATABASE shop;Catatan penting: DROP DATABASE tidak bisa dijalankan saat masih terhubung ke database yang bersangkutan. Pindah dulu, misalnya ke database postgres, sebelum menghapus shop.
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email TEXT NOT NULL UNIQUE,
full_name TEXT NOT NULL,
age INTEGER CHECK (age >= 17),
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);Perhatikan elemen-elemennya: SERIAL PRIMARY KEY untuk auto-increment id, NOT NULL untuk kolom wajib, UNIQUE untuk email, CHECK untuk validasi nilai, dan DEFAULT now() untuk timestamp otomatis. Kita akan membedah tipe data dan constraint ini lebih dalam di episode 3.
Struktur tabel jarang berubah total dalam satu kali pembuatan. ALTER TABLE adalah perintah untuk evolusi struktur:
ALTER TABLE users ADD COLUMN phone TEXT;
ALTER TABLE users ALTER COLUMN phone SET NOT NULL;
ALTER TABLE users DROP COLUMN phone;
ALTER TABLE users RENAME TO members;Lalu dua perintah yang sering tertukar artinya:
TRUNCATE TABLE: menghapus SEMUA baris dengan cepat, tapi tabel dan strukturnya tetap ada. Tidak bisa dipakai dengan WHERE.DROP TABLE: menghapus tabel beserta strukturnya dan seluruh isinya secara permanen.TRUNCATE TABLE orders;
DROP TABLE orders;Danger
DROP TABLE dan TRUNCATE TABLE adalah operasi yang tidak bisa di-undo. Saat kalian menghapus tabel di database production, tidak ada "recycle bin". Selalu verifikasi nama tabel sebelum mengeksekusi, atau matikan autocommit dan jalankan di dalam transaction agar bisa ROLLBACK (kita pelajari di episode 11).
Semua DDL di atas bisa dieksekusi langsung di psql. Untuk memastikan hasilnya, gunakan meta-command yang sudah kita pelajari di episode 0:
\dt
\d users\dt menampilkan daftar tabel, sedangkan \d users menampilkan detail kolom, tipe, dan constraint dari tabel users.
| # | Kesalahan | Gejala | Solusi |
|---|---|---|---|
| 1 | Lupa unique constraint pada email | User bisa daftar dengan email ganda | Tambah UNIQUE saat CREATE TABLE |
| 2 | Menaruh FK di tabel yang salah | Relasi terbalik dan query JOIN jadi aneh | Ingat aturan: tabel "banyak" yang menyimpan FK |
| 3 | DROP DATABASE sambil connect ke database itu | Error database is being accessed by other users | Pindah dulu ke database lain |
| 4 | TRUNCATE tanpa paham efeknya | Semua data hilang tanpa peringatan | Pastikan ini benar-benar yang kalian inginkan |
Di episode 2 ini kita sudah membangun fondasi desain yang kokoh: memodelkan data dengan Entity Relationship Diagram, memahami peran Primary Key, Foreign Key, dan Unique Constraint, menguasai prinsip normalisasi dari 1NF hingga BCNF, serta mempraktikkan DDL untuk membuat, mengubah, dan menghapus database serta tabel.
Inti yang harus dibawa pulang:
CREATE/ALTER/DROP/TRUNCATE adalah toolkit DDL yang wajib dikuasai.Di episode 3 selanjutnya, kita akan menyelam lebih dalam ke bahan dasar database: Data Types di PostgreSQL dan manajemen constraint — mulai dari tipe numerik, string, tanggal-waktu, boolean, dan UUID, hingga berbagai constraint seperti NOT NULL, FOREIGN KEY dengan referential action, dan CHECK. Struktur kalian akan berubah dari "bisa membuat tabel" menjadi "membuat tabel yang benar".