Episode ini membahas tipe data utama PostgreSQL: numerik, karakter, tanggal dan waktu, boolean, serta UUID. Selain itu dibahas manajemen constraint seperti NOT NULL, UNIQUE, PRIMARY KEY, FOREIGN KEY dengan referential action, dan CHECK untuk menjaga integritas data.

Selamat datang di episode 3 series Belajar SQL PostgreSQL! Pada episode 2, kita sudah belajar merancang tabel dengan DDL. Sekarang kita akan menyelam lebih dalam ke bahan dasar dari setiap tabel: tipe data dan constraint. Pemahaman keduanya menentukan seberapa aman, cepat, dan benar database kalian nantinya.
Di episode ini, kita akan membahas tipe data utama PostgreSQL satu per satu — numerik, karakter, tanggal dan waktu, boolean, dan UUID — lalu mempelajari cara mengelola constraint dengan benar.
PostgreSQL menyediakan keluarga tipe numerik yang cukup lengkap, dan setiap tipe punya kasus penggunaan yang berbeda. Memilih tipe yang tepat adalah keputusan desain yang penting.
| Tipe | Rentang nilai | Kasus penggunaan |
|---|---|---|
SMALLINT | -32.768 s/d 32.767 | Menyimpan angka kecil: quantity |
INTEGER / INT | -2,1 milyar s/d 2,1 milyar | Default untuk id dan counter |
BIGINT | Rentang ±9,2 triliun | Data dengan volume raksasa |
NUMERIC(p,s) | Presisi tepat, bisa diset | Uang, perhitungan presisi |
REAL | Floating point 4 byte | Pengukuran yang presisinya tidak kritis |
SELECT 0.1::REAL + 0.2::REAL AS floating_error;
SELECT 0.1::NUMERIC(10,2) + 0.2::NUMERIC(10,2) AS exact_sum;Warning
Aturan emasnya: jangan pernah menyimpan uang dengan REAL atau DOUBLE PRECISION. Error pembulatan floating point bisa membuat laporan keuangan selisih receh yang kemudian menjadi selisih besar saat dikalikan jutaan transaksi. Untuk uang, selalu gunakan NUMERIC atau BIGINT dalam satuan sen.
Untuk kolom auto-increment, generasi lama memakai SERIAL; standar SQL modern menyarankan GENERATED ALWAYS AS IDENTITY yang lebih eksplisit dan tidak bisa di-override.
CREATE TABLE old_style (
id SERIAL PRIMARY KEY
);
CREATE TABLE modern_style (
id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY
);Dengan GENERATED ALWAYS, PostgreSQL menolak nilai id manual — database yang mengelola nilainya sendiri, menghindari bug duplikat id.
PostgreSQL menyediakan tiga tipe untuk teks: VARCHAR(n) (teks dengan batas panjang), CHAR(n) (teks panjang tetap, nilai pendek dipadding spasi), dan TEXT (teks tanpa batas panjang). Satu fakta penting: tidak ada performance penalty antara VARCHAR dan TEXT — batasan panjang di VARCHAR(n) murni validasi, bukan optimasi storage.
CREATE TABLE articles (
title VARCHAR(200) NOT NULL,
slug TEXT NOT NULL,
country CHAR(2) NOT NULL
);Tip
Di PostgreSQL, gunakan TEXT sebagai default untuk kolom teks, dan baru pakai VARCHAR(n) ketika kalian memang ingin memberlakukan batas panjang sebagai business rule. Sedangkan CHAR(n) jarang dibutuhkan — pemakaiannya paling masuk akal untuk kode berukuran tetap seperti kode negara ISO.
TIMESTAMP: tanggal dan jam TANPA informasi timezone. Nilai seperti 2026-08-03 10:00:00 dimaknai "apa adanya".TIMESTAMPTZ: tanggal dan jam DENGAN timezone awareness. Nilai disimpan dalam UTC secara internal, dan dirender sesuai timezone sesi.SELECT now() AS waktu_sekarang;
SELECT now() AT TIME ZONE 'Asia/Jakarta' AS waktu_jakarta;
SHOW timezone;SELECT now() + INTERVAL '7 days' AS seminggu_lagi;
SELECT age('2026-08-03', '2020-01-01') AS umur_akun;CREATE TABLE users (
id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
email TEXT NOT NULL UNIQUE,
is_active BOOLEAN NOT NULL DEFAULT TRUE
);UUID adalah identitas 128-bit yang praktis mustahil bertabrakan antar sistem.
CREATE EXTENSION IF NOT EXISTS pgcrypto;
CREATE TABLE sessions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id INTEGER NOT NULL,
token TEXT NOT NULL
);Fungsi gen_random_uuid() menghasilkan UUID v4 secara acak; di PostgreSQL 13+ tersedia bawaan tanpa extension.
Constraint adalah "polisi" database yang memastikan data yang masuk selalu memenuhi aturan — pertahanan terakhir yang bekerja bahkan jika aplikasi lupa memvalidasi.
CREATE TABLE customers (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email TEXT NOT NULL UNIQUE,
phone TEXT,
referral_code TEXT UNIQUE
);NOT NULL: kolom wajib diisi; phone di atas boleh kosong karena tanpa constraint.UNIQUE: tidak boleh ada duplikat nilai; satu email hanya untuk satu customer.PRIMARY KEY: kombinasi NOT NULL + UNIQUE + identitas baris.| Action | Perilaku |
|---|---|
ON DELETE CASCADE | Hapus baris anak ikut-ikutan saat induk dihapus |
ON DELETE RESTRICT | Tolak penghapusan jika masih ada baris anak |
ON DELETE SET NULL | Set kolom FK anak menjadi NULL |
ON UPDATE CASCADE | Ikutkan perubahan nilai PK induk ke FK anak |
CREATE TABLE orders (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
customer_id UUID NOT NULL REFERENCES customers(id) ON DELETE CASCADE,
total NUMERIC(12,2) NOT NULL CHECK (total >= 0)
);
CREATE TABLE order_items (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
order_id UUID NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
product_name TEXT NOT NULL
);CHECK adalah validasi nilai kustom yang bebas — pertahanan terakhir yang bekerja bahkan jika aplikasi lupa memvalidasi.
CREATE TABLE products (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL,
price NUMERIC(12,2) NOT NULL CHECK (price > 0),
stock INTEGER NOT NULL DEFAULT 0 CHECK (stock >= 0)
);Inti yang harus dibawa pulang:
NUMERIC untuk uang, bukan REAL — floating point bisa mengganggu presisi.GENERATED ALWAYS AS IDENTITY daripada SERIAL untuk auto-increment modern.TIMESTAMPTZ untuk menyimpan titik waktu, kecuali ada alasan khusus.CHECK, FK dengan referential action, dan UNIQUE adalah teman terbaik kalian.Di episode 4 selanjutnya, kita mulai mengisi database dengan data: Data Manipulation Language (DML) dan Basic Querying — mulai dari INSERT untuk memasukkan data, UPDATE untuk mengubah, DELETE untuk menghapus, hingga fitur khas PostgreSQL RETURNING yang sangat berguna di dunia nyata. Siapkan tabel yang tadi kalian buat, karena episode berikutnya penuh praktik!