BelajarKoding Logobelajarkoding

Platform belajar web development Indonesia. Artikel, cheat sheets, roadmap, dan code challenges untuk developer Indonesia.

Navigasi

  • Artikel
  • Cheat Sheets
  • Roadmap
  • Challenges
  • Pricing
  • Search

Produk Lain

  • JagoHermes
  • KelasClaude
  • KilatKoding
  • BelajarVibeCoding
  • JualanKoding

Support

  • Privacy Policy
  • Terms of Service
  • Email

© 2026 BelajarKoding. All rights reserved.

Galih PratamaBagian dari ekosistem Galih Pratama
belajarkoding LogobyGalih Pratama
RoadmapArtikelCheat SheetsChallengesUpgrade
belajarkoding LogobyGalih Pratama
RoadmapArtikelCheat SheetsChallengesUpgrade
belajarkoding LogobyGalih Pratama
RoadmapArtikelCheat SheetsChallengesUpgrade

Daftar Isi

psql CommandsDatabase OperationsTable OperationsData TypesCRUD OperationsINSERTSELECTUPDATEDELETEJoinsConstraintsIndexesTransactionsJSON OperationsViewsFunctionsTriggersPattern UmumUUID Primary KeySoft DeleteAuto-Update TimestampPaginationPerformanceEXPLAINVacuumBackup & RestoreUser ManagementConnection from CodeNode.js (pg)PrismaCommon FunctionsDocker SetupBest PracticesResources
PostgreSQLDatabaseSQLBackend

PostgreSQL Cheat Sheet

Quick reference PostgreSQL. SQL commands, data types, joins, indexes, dan common queries untuk relational database development.

SQL12 min read2.226 kata
Silakan login atau daftar untuk membaca cheat sheet ini.

#psql Commands

Perintah-perintah command line untuk berinteraksi dengan PostgreSQL database menggunakan psql client.

bash
# Login
psql -U username -d database
 
# List databases
\l
 
# Connect to database
\c database_name
 
# List tables
\dt
 
# Describe table
\d table_name
 
# List indexes
\di
 
# List users/roles
\du
 
# Execute SQL file
\i file.sql
 
# Export query to file
\o output.txt
 
# Toggle timing
\timing
 
# Exit
\q

#Database Operations

Operasi-operasi dasar untuk membuat, menghapus, dan mengelola database.

sql
-- Create database
CREATE DATABASE mydb;
 
-- Drop database
DROP DATABASE mydb;
DROP DATABASE IF EXISTS mydb;
 
-- Rename database
ALTER DATABASE mydb RENAME TO newdb;

#Table Operations

Operasi untuk membuat, memodifikasi, dan menghapus tabel dalam database.

sql
-- Create table
CREATE TABLE users (
 id SERIAL PRIMARY KEY,
 name VARCHAR(100) NOT NULL,
 email VARCHAR(255) UNIQUE,
 age INTEGER CHECK (age >= 18),
 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
 
-- Drop table
DROP TABLE users;
DROP TABLE IF EXISTS users CASCADE;
 
-- Rename table
ALTER TABLE users RENAME TO customers;
 
-- Add column
ALTER TABLE users ADD COLUMN phone VARCHAR(20);
 
-- Drop column
ALTER TABLE users DROP COLUMN phone;
 
-- Rename column
ALTER TABLE users RENAME COLUMN name TO full_name;
 
-- Change column type
ALTER TABLE users ALTER COLUMN age TYPE SMALLINT;
 
-- Add constraint
ALTER TABLE users ADD CONSTRAINT unique_email UNIQUE (email);

#Data Types

Berbagai tipe data yang tersedia di PostgreSQL untuk kolom tabel.

TypeDescriptionExample
SERIALAuto-incrementing integerid SERIAL PRIMARY KEY
INTEGERWhole numbersage INTEGER
BIGINTLarge integersviews BIGINT
DECIMAL(10,2)Exact decimalprice DECIMAL(10,2)
REALFloat (6 digits)rating REAL
VARCHAR(n)Variable string (max n)name VARCHAR(100)
TEXTUnlimited stringcontent TEXT
CHAR(n)Fixed length stringcode CHAR(5)
BOOLEANTRUE/FALSEactive BOOLEAN
DATEDate onlybirthdate DATE
TIMETime onlystart_time TIME
TIMESTAMPDate + timecreated_at TIMESTAMP
TIMESTAMPTZTimestamp with timezonelogged_at TIMESTAMPTZ
UUIDUnique identifierid UUID
JSONJSON data (text)data JSON
JSONBBinary JSON (faster)settings JSONB
INTEGER[]Array of integerstags INTEGER[]
VARCHAR(100)[]Array of stringsemails VARCHAR(100)[]

#CRUD Operations

Operasi dasar Create, Read, Update, Delete pada data tabel.

#INSERT

Menambahkan data baru ke dalam tabel.

sql
-- Single row
INSERT INTO users (name, email) VALUES ('Galih', 'galih@example.com');
 
-- Multiple rows
INSERT INTO users (name, email) VALUES
 ('Budi', 'budi@example.com'),
 ('Ani', 'ani@example.com');
 
-- Return inserted row
INSERT INTO users (name, email)
VALUES ('Rina', 'rina@example.com')
RETURNING *;
 
-- Insert from SELECT
INSERT INTO users_backup SELECT * FROM users;

#SELECT

Mengambil data dari tabel dengan berbagai kondisi dan filter.

sql
-- Select all
SELECT * FROM users;
 
-- Select specific columns
SELECT name, email FROM users;
 
-- WHERE clause
SELECT * FROM users WHERE age >= 25;
 
-- Multiple conditions
SELECT * FROM users WHERE age >= 25 AND active = TRUE;
 
-- OR condition
SELECT * FROM users WHERE age < 20 OR age > 60;
 
-- IN operator
SELECT * FROM users WHERE id IN (1, 2, 3);
 
-- BETWEEN
SELECT * FROM users WHERE age BETWEEN 25 AND 35;
 
-- LIKE (pattern matching)
SELECT * FROM users WHERE email LIKE '%@gmail.com';
 
-- ILIKE (case-insensitive)
SELECT * FROM users WHERE name ILIKE '%john%';
 
-- IS NULL
SELECT * FROM users WHERE phone IS NULL;
 
-- ORDER BY
SELECT * FROM users ORDER BY created_at DESC;
 
-- LIMIT & OFFSET
SELECT * FROM users LIMIT 10 OFFSET 20;
 
-- DISTINCT
SELECT DISTINCT age FROM users;
 
-- Aggregate functions
SELECT COUNT(*) FROM users;
SELECT AVG(age) FROM users;
SELECT SUM(price) FROM products;
SELECT MAX(age), MIN(age) FROM users;
 
-- GROUP BY
SELECT age, COUNT(*) as count
FROM users
GROUP BY age;
 
-- HAVING (filter after GROUP BY)
SELECT age, COUNT(*) as count
FROM users
GROUP BY age
HAVING COUNT(*) > 5;

#UPDATE

Mengubah data yang sudah ada dalam tabel.

sql
-- Update single row
UPDATE users SET name = 'Galih Pratama' WHERE id = 1;
 
-- Update multiple columns
UPDATE users
SET name = 'Budi', age = 31, updated_at = NOW()
WHERE id = 2;
 
-- Update with calculation
UPDATE users SET age = age + 1 WHERE id = 3;
 
-- Update all rows (careful!)
UPDATE users SET updated_at = NOW();
 
-- Update with RETURNING
UPDATE users SET age = 26 WHERE id = 1 RETURNING *;

#DELETE

Menghapus data dari tabel.

sql
-- Delete specific rows
DELETE FROM users WHERE id = 1;
 
-- Delete with condition
DELETE FROM users WHERE age < 18;
 
-- Delete all rows (careful!)
DELETE FROM users;
 
-- Delete with RETURNING
DELETE FROM users WHERE id = 1 RETURNING *;
 
-- Truncate (faster, resets sequences)
TRUNCATE TABLE users;

#Joins

Menggabungkan data dari multiple tabel berdasarkan relasi.

sql
-- INNER JOIN (matching rows only)
SELECT u.name, p.title
FROM users u
INNER JOIN posts p ON u.id = p.user_id;
 
-- LEFT JOIN (all from left table)
SELECT u.name, p.title
FROM users u
LEFT JOIN posts p ON u.id = p.user_id;
 
-- RIGHT JOIN (all from right table)
SELECT u.name, p.title
FROM users u
RIGHT JOIN posts p ON u.id = p.user_id;
 
-- FULL OUTER JOIN (all from both)
SELECT u.name, p.title
FROM users u
FULL OUTER JOIN posts p ON u.id = p.user_id;
 
-- Multiple joins
SELECT u.name, p.title, c.content
FROM users u
JOIN posts p ON u.id = p.user_id
JOIN comments c ON p.id = c.post_id;

#Constraints

Aturan-aturan yang membatasi tipe data dan relasi dalam tabel.

sql
-- PRIMARY KEY
CREATE TABLE users (
 id SERIAL PRIMARY KEY
);
 
-- FOREIGN KEY
CREATE TABLE posts (
 id SERIAL PRIMARY KEY,
 user_id INTEGER REFERENCES users(id) ON DELETE CASCADE
);
 
-- UNIQUE
CREATE TABLE users (
 email VARCHAR(255) UNIQUE
);
 
-- CHECK
CREATE TABLE users (
 age INTEGER CHECK (age >= 18)
);
 
-- NOT NULL
CREATE TABLE users (
 email VARCHAR(255) NOT NULL
);
 
-- DEFAULT
CREATE TABLE users (
 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
 active BOOLEAN DEFAULT TRUE
);
 
-- Add constraint to existing table
ALTER TABLE users ADD CONSTRAINT unique_email UNIQUE (email);
ALTER TABLE users ADD CONSTRAINT age_check CHECK (age >= 18);

#Indexes

sql
-- Create index
CREATE INDEX idx_users_email ON users(email);
 
-- Unique index
CREATE UNIQUE INDEX idx_users_email_unique ON users(email);
 
-- Multiple columns
CREATE INDEX idx_users_name_age ON users(name, age);
 
-- Partial index (conditional)
CREATE INDEX idx_active_users ON users(email) WHERE active = TRUE;
 
-- Drop index
DROP INDEX idx_users_email;
 
-- List indexes
\di

#Transactions

sql
-- Start transaction
BEGIN;
 
-- Run queries
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
 
-- Save changes
COMMIT;
 
-- Or undo changes
ROLLBACK;
 
-- Savepoint (partial rollback)
BEGIN;
UPDATE users SET name = 'Test' WHERE id = 1;
SAVEPOINT my_savepoint;
UPDATE users SET age = 99 WHERE id = 1;
ROLLBACK TO my_savepoint; -- Undo age update only
COMMIT;

#JSON Operations

sql
-- Create table with JSONB
CREATE TABLE products (
 id SERIAL PRIMARY KEY,
 data JSONB
);
 
-- Insert JSON
INSERT INTO products (data) VALUES
 ('{"name": "Laptop", "price": 1000, "brand": "Dell"}');
 
-- Query JSON field
SELECT data->>'name' as name FROM products;
 
-- Nested JSON
SELECT data->'specs'->>'cpu' as cpu FROM products;
 
-- Where clause
SELECT * FROM products WHERE data->>'brand' = 'Dell';
 
-- Check if key exists
SELECT * FROM products WHERE data ? 'warranty';
 
-- Contains (@>)
SELECT * FROM products WHERE data @> '{"brand": "Dell"}';
 
-- Update JSON
UPDATE products
SET data = data || '{"warranty": "2 years"}'
WHERE id = 1;
 
-- Remove key
UPDATE products
SET data = data - 'old_field'
WHERE id = 1;
 
-- Create index on JSON field
CREATE INDEX idx_products_brand ON products((data->>'brand'));

#Views

sql
-- Create view
CREATE VIEW active_users AS
SELECT id, name, email
FROM users
WHERE active = TRUE;
 
-- Use view
SELECT * FROM active_users;
 
-- Materialized view (cached)
CREATE MATERIALIZED VIEW user_stats AS
SELECT age, COUNT(*) as count
FROM users
GROUP BY age;
 
-- Refresh materialized view
REFRESH MATERIALIZED VIEW user_stats;
 
-- Drop view
DROP VIEW active_users;

#Functions

sql
-- Simple function
CREATE FUNCTION get_user_count() RETURNS INTEGER AS $$
BEGIN
 RETURN (SELECT COUNT(*) FROM users);
END;
$$ LANGUAGE plpgsql;
 
-- Use function
SELECT get_user_count();
 
-- Function with parameters
CREATE FUNCTION get_users_by_age(min_age INTEGER)
RETURNS TABLE(id INTEGER, name VARCHAR) AS $$
BEGIN
 RETURN QUERY
 SELECT users.id, users.name FROM users WHERE age >= min_age;
END;
$$ LANGUAGE plpgsql;
 
-- Use function
SELECT * FROM get_users_by_age(25);
 
-- Drop function
DROP FUNCTION get_user_count();

#Triggers

sql
-- Function for trigger
CREATE OR REPLACE FUNCTION update_updated_at()
RETURNS TRIGGER AS $$
BEGIN
 NEW.updated_at = CURRENT_TIMESTAMP;
 RETURN NEW;
END;
$$ LANGUAGE plpgsql;
 
-- Create trigger
CREATE TRIGGER update_users_updated_at
BEFORE UPDATE ON users
FOR EACH ROW
EXECUTE FUNCTION update_updated_at();
 
-- Drop trigger
DROP TRIGGER update_users_updated_at ON users;

#Pattern Umum

#UUID Primary Key

sql
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
 
CREATE TABLE users (
 id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
 name VARCHAR(100)
);

#Soft Delete

sql
CREATE TABLE users (
 id SERIAL PRIMARY KEY,
 name VARCHAR(100),
 deleted_at TIMESTAMP NULL
);
 
-- Soft delete
UPDATE users SET deleted_at = NOW() WHERE id = 1;
 
-- Query active only
SELECT * FROM users WHERE deleted_at IS NULL;

#Auto-Update Timestamp

sql
CREATE TABLE posts (
 id SERIAL PRIMARY KEY,
 title VARCHAR(200),
 updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
 
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
 NEW.updated_at = NOW();
 RETURN NEW;
END;
$$ LANGUAGE plpgsql;
 
CREATE TRIGGER update_posts_updated_at
BEFORE UPDATE ON posts
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();

#Pagination

sql
-- Offset-based (simple)
SELECT * FROM users ORDER BY id LIMIT 10 OFFSET 20;
 
-- Cursor-based (better performance)
SELECT * FROM users WHERE id > 20 ORDER BY id LIMIT 10;

#Performance

#EXPLAIN

sql
-- Show query plan
EXPLAIN SELECT * FROM users WHERE email = 'test@example.com';
 
-- Show actual execution
EXPLAIN ANALYZE SELECT * FROM users WHERE age > 25;

#Vacuum

sql
-- Clean up dead rows
VACUUM users;
 
-- Full vacuum (more thorough)
VACUUM FULL users;
 
-- Analyze (update statistics)
ANALYZE users;
 
-- Combined
VACUUM ANALYZE users;

#Backup & Restore

bash
# Backup database
pg_dump -U postgres mydb > backup.sql
 
# Backup with compression
pg_dump -U postgres mydb | gzip > backup.sql.gz
 
# Restore database
psql -U postgres mydb < backup.sql
 
# Restore from compressed
gunzip < backup.sql.gz | psql -U postgres mydb
 
# Backup all databases
pg_dumpall -U postgres > all_dbs.sql

#User Management

sql
-- Create user
CREATE USER myuser WITH PASSWORD 'mypassword';
 
-- Grant privileges
GRANT ALL PRIVILEGES ON DATABASE mydb TO myuser;
GRANT SELECT, INSERT, UPDATE ON users TO myuser;
 
-- Revoke privileges
REVOKE ALL PRIVILEGES ON DATABASE mydb FROM myuser;
 
-- Change password
ALTER USER myuser WITH PASSWORD 'newpassword';
 
-- Drop user
DROP USER myuser;

#Connection from Code

#Node.js (pg)

javascript
const { Pool } = require('pg');
 
const pool = new Pool({
 user: 'postgres',
 host: 'localhost',
 database: 'mydb',
 password: 'password',
 port: 5432,
});
 
// Query
const result = await pool.query('SELECT * FROM users WHERE id = $1', [1]);
console.log(result.rows);

#Prisma

prisma
datasource db {
 provider = "postgresql"
 url   = env("DATABASE_URL")
}
 
model User {
 id  Int   @id @default(autoincrement())
 email String @unique
 name String?
 posts Post[]
}
 
model Post {
 id    Int  @id @default(autoincrement())
 title   String
 author  User  @relation(fields: [authorId], references: [id])
 authorId Int
}
javascript
const { PrismaClient } = require('@prisma/client');
const prisma = new PrismaClient();
 
const users = await prisma.user.findMany({ include: { posts: true } });

#Common Functions

sql
-- String functions
LENGTH('hello')        -- 5
UPPER('hello')         -- 'HELLO'
LOWER('HELLO')         -- 'hello'
CONCAT('Hello', ' ', 'World') -- 'Hello World'
SUBSTRING('hello' FROM 1 FOR 2) -- 'he'
TRIM(' hello ')       -- 'hello'
 
-- Date functions
NOW()             -- Current timestamp
CURRENT_DATE          -- Current date
CURRENT_TIME          -- Current time
AGE(timestamp '2000-01-01')  -- Age from date
EXTRACT(YEAR FROM NOW())    -- Extract year
 
-- Math functions
ABS(-5)            -- 5
ROUND(3.14159, 2)       -- 3.14
CEIL(3.1)           -- 4
FLOOR(3.9)           -- 3
RANDOM()            -- Random 0-1
 
-- Aggregate functions
COUNT(*)
SUM(column)
AVG(column)
MAX(column)
MIN(column)
STRING_AGG(column, ',')    -- Concatenate rows

#Docker Setup

yaml
# docker-compose.yml
version: '3.8'
services:
 postgres:
  image: postgres:16
  environment:
   POSTGRES_USER: postgres
   POSTGRES_PASSWORD: mypassword
   POSTGRES_DB: mydb
  ports:
   - "5432:5432"
  volumes:
   - postgres_data:/var/lib/postgresql/data
 
volumes:
 postgres_data:
bash
docker-compose up -d
docker exec -it postgres_container psql -U postgres

#Best Practices

  • Use indexes on WHERE/JOIN columns
  • Avoid SELECT * (specify columns)
  • Use LIMIT for large tables
  • Use transactions for related operations
  • Add foreign key constraints
  • Use connection pooling
  • Backup database regularly
  • Use prepared statements (prevent SQL injection)
  • Monitor query performance with EXPLAIN
  • Normalize data to avoid duplication

#Resources

  • PostgreSQL Documentation
  • PostgreSQL Tutorial
  • SQL Teaching
  • PGExercises

Happy querying! 🐘

Baca Cheat Sheet Lengkap

Login atau daftar akun gratis untuk membaca cheat sheet ini.

LoginDaftar Gratis
Share: