Tables and Data Types
1. Table Basic Concepts
A table is a structure that stores data organized into rows and columns.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β users ν
μ΄λΈ β
ββββββββββ¬βββββββββββ¬ββββββββββββββββββ¬ββββββββββββββββ€
β id β name β email β created_at β
ββββββββββΌβββββββββββΌββββββββββββββββββΌββββββββββββββββ€
β 1 β κΉμ² μ β kim@email.com β 2024-01-15 β
β 2 β μ΄μν¬ β lee@email.com β 2024-01-16 β
β 3 β λ°λ―Όμ β park@email.com β 2024-01-17 β
ββββββββββ΄βββββββββββ΄ββββββββββββββββββ΄ββββββββββββββββ
컬λΌ(Column) β κ° νμ νλμ λ μ½λ
2. Table Creation
Basic Syntax
CREATE TABLE ν
μ΄λΈλͺ
(
컬λΌλͺ
1 λ°μ΄ν°νμ
[μ μ½μ‘°κ±΄],
컬λΌλͺ
2 λ°μ΄ν°νμ
[μ μ½μ‘°κ±΄],
...
);
Basic Example
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
age INTEGER,
created_at TIMESTAMP DEFAULT NOW()
);
Create Only If Not Exists
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL
);
3. Numeric Data Types
Integer Types
| νμ
|
ν¬κΈ° |
λ²μ |
SMALLINT |
2 bytes |
-32,768 ~ 32,767 |
INTEGER (INT) |
4 bytes |
-2,147,483,648 ~ 2,147,483,647 |
BIGINT |
8 bytes |
-9κ²½ ~ 9κ²½ |
CREATE TABLE products (
id INTEGER,
quantity SMALLINT,
total_sold BIGINT
);
Auto-Increment (Serial)
| νμ
|
λ²μ |
SMALLSERIAL |
1 ~ 32,767 |
SERIAL |
1 ~ 2,147,483,647 |
BIGSERIAL |
1 ~ 9κ²½ |
CREATE TABLE orders (
id SERIAL PRIMARY KEY, -- μλμΌλ‘ 1, 2, 3, ... μ¦κ°
order_date DATE
);
-- PostgreSQL 10+ μμλ IDENTITY κΆμ₯
CREATE TABLE orders (
id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
order_date DATE
);
Floating-Point Types
| νμ
|
μ€λͺ
|
REAL |
4 bytes, 6μ리 μ λ°λ |
DOUBLE PRECISION |
8 bytes, 15μ리 μ λ°λ |
NUMERIC(p, s) |
μ νν μ«μ (p: μ 체 μλ¦Ώμ, s: μμμ μλ¦Ώμ) |
DECIMAL(p, s) |
NUMERICκ³Ό λμΌ |
CREATE TABLE products (
id SERIAL PRIMARY KEY,
price NUMERIC(10, 2), -- μ΅λ 10μ리, μμμ 2μ리 (μ: 99999999.99)
weight REAL, -- λΆλ μμμ
rating DOUBLE PRECISION -- λ μ λ°ν λΆλ μμμ
);
INSERT INTO products (price, weight, rating) VALUES
(19900.00, 1.5, 4.7);
4. Character Data Types
| νμ
|
μ€λͺ
|
CHAR(n) |
κ³ μ κΈΈμ΄ λ¬Έμμ΄ (λ¨λ 곡κ°μ 곡백μΌλ‘ μ±μ) |
VARCHAR(n) |
κ°λ³ κΈΈμ΄ λ¬Έμμ΄ (μ΅λ nμ) |
TEXT |
κΈΈμ΄ μ ν μλ λ¬Έμμ΄ |
CREATE TABLE articles (
id SERIAL PRIMARY KEY,
code CHAR(10), -- νμ 10μ (μ½λ λ±μ μ¬μ©)
title VARCHAR(200), -- μ΅λ 200μ
content TEXT -- κΈΈμ΄ μ ν μμ
);
VARCHAR vs TEXT
-- μ€μ§μ μΌλ‘ ν° μ°¨μ΄ μμ. PostgreSQLμμλ TEXT μ νΈνλ κ²½μ°λ λ§μ
CREATE TABLE posts (
title VARCHAR(255), -- κΈΈμ΄ μ νμ΄ νμν κ²½μ°
body TEXT -- κΈΈμ΄ μ νμ΄ νμ μλ κ²½μ°
);
5. Date/Time Data Types
| νμ
|
μ€λͺ
|
μμ |
DATE |
λ μ§λ§ |
2024-01-15 |
TIME |
μκ°λ§ |
14:30:00 |
TIMESTAMP |
λ μ§ + μκ° |
2024-01-15 14:30:00 |
TIMESTAMPTZ |
λ μ§ + μκ° + νμμ‘΄ |
2024-01-15 14:30:00+09 |
INTERVAL |
μκ° κ°κ²© |
2 days 3 hours |
CREATE TABLE events (
id SERIAL PRIMARY KEY,
event_name VARCHAR(100),
event_date DATE,
start_time TIME,
created_at TIMESTAMP DEFAULT NOW(),
scheduled_at TIMESTAMPTZ,
duration INTERVAL
);
INSERT INTO events (event_name, event_date, start_time, duration) VALUES
('νμ', '2024-01-20', '14:00:00', '2 hours'),
('μν¬μ΅', '2024-01-25', '09:00:00', '1 day');
Date/Time Functions
-- νμ¬ μκ°
SELECT NOW(); -- 2024-01-15 14:30:00.123456+09
SELECT CURRENT_DATE; -- 2024-01-15
SELECT CURRENT_TIME; -- 14:30:00.123456+09
SELECT CURRENT_TIMESTAMP; -- NOW()μ λμΌ
-- λ μ§ μ°μ°
SELECT NOW() + INTERVAL '1 day';
SELECT NOW() - INTERVAL '2 hours';
SELECT '2024-01-20'::DATE - '2024-01-15'::DATE; -- 5 (μΌμ)
-- λ μ§ μΆμΆ
SELECT EXTRACT(YEAR FROM NOW());
SELECT EXTRACT(MONTH FROM NOW());
SELECT EXTRACT(DOW FROM NOW()); -- μμΌ (0=μΌμμΌ)
6. Boolean Data Type
| κ° |
TRUE |
FALSE |
NULL |
| μ
λ ₯ |
true, 't', 'yes', 'y', '1' |
false, 'f', 'no', 'n', '0' |
null |
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
is_active BOOLEAN DEFAULT true,
is_admin BOOLEAN DEFAULT false
);
INSERT INTO users (name, is_active, is_admin) VALUES
('κΉμ² μ', true, false),
('κ΄λ¦¬μ', true, true);
SELECT * FROM users WHERE is_active = true;
SELECT * FROM users WHERE NOT is_admin;
7. JSON Data Types
| νμ
|
μ€λͺ
|
JSON |
JSON ν
μ€νΈ μ μ₯ (λ§€λ² νμ±) |
JSONB |
JSON λ°μ΄λ리 μ μ₯ (μΈλ±μ± κ°λ₯, κΆμ₯) |
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
attributes JSONB
);
INSERT INTO products (name, attributes) VALUES
('λ
ΈνΈλΆ', '{"brand": "Samsung", "ram": 16, "storage": "512GB"}'),
('λ§μ°μ€', '{"brand": "Logitech", "wireless": true, "color": "black"}');
-- JSON λ°μ΄ν° μ‘°ν
SELECT name, attributes->>'brand' AS brand FROM products;
SELECT name, attributes->'ram' AS ram FROM products;
-- JSON 쑰건 κ²μ
SELECT * FROM products WHERE attributes->>'brand' = 'Samsung';
SELECT * FROM products WHERE (attributes->>'ram')::int >= 16;
-- JSON λ°°μ΄
INSERT INTO products (name, attributes) VALUES
('ν€λ³΄λ', '{"brand": "Keychron", "colors": ["white", "black", "gray"]}');
SELECT attributes->'colors'->0 FROM products WHERE name = 'ν€λ³΄λ'; -- "white"
8. Other Data Types
UUID
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE TABLE sessions (
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
user_id INTEGER,
created_at TIMESTAMP DEFAULT NOW()
);
INSERT INTO sessions (user_id) VALUES (1);
-- id: 550e8400-e29b-41d4-a716-446655440000
Arrays
CREATE TABLE posts (
id SERIAL PRIMARY KEY,
title VARCHAR(200),
tags TEXT[]
);
INSERT INTO posts (title, tags) VALUES
('PostgreSQL μ
λ¬Έ', ARRAY['database', 'postgresql', 'sql']),
('Docker μμνκΈ°', '{"docker", "container", "devops"}');
-- λ°°μ΄ μ‘°ν
SELECT title, tags[1] FROM posts; -- 첫 λ²μ§Έ μμ
-- λ°°μ΄ ν¬ν¨ μ¬λΆ
SELECT * FROM posts WHERE 'docker' = ANY(tags);
SELECT * FROM posts WHERE tags @> ARRAY['sql'];
ENUM
CREATE TYPE mood AS ENUM ('happy', 'sad', 'neutral');
CREATE TABLE user_moods (
id SERIAL PRIMARY KEY,
user_id INTEGER,
current_mood mood
);
INSERT INTO user_moods (user_id, current_mood) VALUES (1, 'happy');
9. Constraints
PRIMARY KEY
-- λ¨μΌ μ»¬λΌ κΈ°λ³Έν€
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100)
);
-- λ³΅ν© κΈ°λ³Έν€
CREATE TABLE order_items (
order_id INTEGER,
product_id INTEGER,
quantity INTEGER,
PRIMARY KEY (order_id, product_id)
);
NOT NULL
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL, -- NULL νμ© μν¨
email VARCHAR(255) NOT NULL
);
UNIQUE
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL, -- μ€λ³΅ λΆκ°
phone VARCHAR(20) UNIQUE -- μ€λ³΅ λΆκ° (NULLμ μ¬λ¬ κ° κ°λ₯)
);
-- λ³΅ν© μ λν¬
CREATE TABLE memberships (
user_id INTEGER,
group_id INTEGER,
UNIQUE (user_id, group_id)
);
DEFAULT
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
status VARCHAR(20) DEFAULT 'pending',
quantity INTEGER DEFAULT 1,
created_at TIMESTAMP DEFAULT NOW()
);
INSERT INTO orders DEFAULT VALUES; -- λͺ¨λ μ»¬λΌ κΈ°λ³Έκ° μ¬μ©
CHECK
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
price NUMERIC(10, 2) CHECK (price > 0),
quantity INTEGER CHECK (quantity >= 0),
discount NUMERIC(3, 2) CHECK (discount >= 0 AND discount <= 1)
);
-- μ΄λ¦ μλ μ μ½μ‘°κ±΄
CREATE TABLE employees (
id SERIAL PRIMARY KEY,
age INTEGER,
salary NUMERIC(10, 2),
CONSTRAINT valid_age CHECK (age >= 18 AND age <= 100),
CONSTRAINT positive_salary CHECK (salary > 0)
);
FOREIGN KEY
-- λΆλͺ¨ ν
μ΄λΈ
CREATE TABLE categories (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL
);
-- μμ ν
μ΄λΈ
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
category_id INTEGER REFERENCES categories(id)
);
-- μμΈ μ΅μ
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
category_id INTEGER,
FOREIGN KEY (category_id) REFERENCES categories(id)
ON DELETE CASCADE -- λΆλͺ¨ μμ μ μμλ μμ
ON UPDATE CASCADE -- λΆλͺ¨ μμ μ μμλ μμ
);
ON DELETE / ON UPDATE Options
| μ΅μ
|
μ€λͺ
|
CASCADE |
λΆλͺ¨μ ν¨κ» μμ /μμ |
SET NULL |
NULLλ‘ μ€μ |
SET DEFAULT |
κΈ°λ³Έκ°μΌλ‘ μ€μ |
RESTRICT |
μμ /μμ λΆκ° (κΈ°λ³Έκ°) |
NO ACTION |
RESTRICTμ μ μ¬ |
10. Table Modification
Add Column
ALTER TABLE users ADD COLUMN phone VARCHAR(20);
ALTER TABLE users ADD COLUMN is_verified BOOLEAN DEFAULT false;
Drop Column
ALTER TABLE users DROP COLUMN phone;
ALTER TABLE users DROP COLUMN IF EXISTS phone;
Change Column Type
ALTER TABLE users ALTER COLUMN name TYPE VARCHAR(200);
ALTER TABLE users ALTER COLUMN age TYPE SMALLINT;
-- λ°μ΄ν° λ³νμ΄ νμν κ²½μ°
ALTER TABLE users ALTER COLUMN price TYPE INTEGER USING price::INTEGER;
Rename Column
ALTER TABLE users RENAME COLUMN name TO full_name;
Add/Drop Constraints
-- NOT NULL μΆκ°
ALTER TABLE users ALTER COLUMN email SET NOT NULL;
-- NOT NULL μ κ±°
ALTER TABLE users ALTER COLUMN email DROP NOT NULL;
-- DEFAULT μ€μ
ALTER TABLE users ALTER COLUMN status SET DEFAULT 'active';
-- DEFAULT μ κ±°
ALTER TABLE users ALTER COLUMN status DROP DEFAULT;
-- μ μ½μ‘°κ±΄ μΆκ°
ALTER TABLE users ADD CONSTRAINT users_email_unique UNIQUE (email);
ALTER TABLE users ADD CONSTRAINT valid_age CHECK (age >= 0);
-- μ μ½μ‘°κ±΄ μμ
ALTER TABLE users DROP CONSTRAINT users_email_unique;
Rename Table
ALTER TABLE users RENAME TO members;
11. Table Deletion
-- κΈ°λ³Έ μμ
DROP TABLE users;
-- μ‘΄μ¬νλ κ²½μ°μλ§ μμ
DROP TABLE IF EXISTS users;
-- μμ‘΄ κ°μ²΄μ ν¨κ» μμ
DROP TABLE users CASCADE;
-- ν
μ΄λΈ λͺ©λ‘
\dt
-- ν
μ΄λΈ ꡬ쑰
\d users
-- μμΈ μ 보
\d+ users
-- SQL μΏΌλ¦¬λ‘ νμΈ
SELECT
column_name,
data_type,
is_nullable,
column_default
FROM information_schema.columns
WHERE table_name = 'users';
13. Practice Examples
-- 1. μ¬μ©μ ν
μ΄λΈ
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
name VARCHAR(100) NOT NULL,
phone VARCHAR(20),
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- 2. μΉ΄ν
κ³ λ¦¬ ν
μ΄λΈ
CREATE TABLE categories (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
parent_id INTEGER REFERENCES categories(id),
created_at TIMESTAMP DEFAULT NOW()
);
-- 3. μν ν
μ΄λΈ
CREATE TABLE products (
id SERIAL PRIMARY KEY,
category_id INTEGER REFERENCES categories(id),
name VARCHAR(200) NOT NULL,
description TEXT,
price NUMERIC(12, 2) NOT NULL CHECK (price >= 0),
stock INTEGER DEFAULT 0 CHECK (stock >= 0),
attributes JSONB,
is_available BOOLEAN DEFAULT true,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- 4. μ£Όλ¬Έ ν
μ΄λΈ
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id),
status VARCHAR(20) DEFAULT 'pending' CHECK (
status IN ('pending', 'paid', 'shipped', 'delivered', 'cancelled')
),
total_amount NUMERIC(12, 2) NOT NULL,
shipping_address TEXT NOT NULL,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- 5. μ£Όλ¬Έ μμΈ ν
μ΄λΈ
CREATE TABLE order_items (
id SERIAL PRIMARY KEY,
order_id INTEGER REFERENCES orders(id) ON DELETE CASCADE,
product_id INTEGER REFERENCES products(id),
quantity INTEGER NOT NULL CHECK (quantity > 0),
unit_price NUMERIC(12, 2) NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);
-- ν
μ΄λΈ ꡬ쑰 νμΈ
\dt
\d products
Next Steps
Learn about data insertion, querying, updating, and deletion in 04_CRUD_Basics.md!