PostgreSQL 表操作 #
表概述 #
表是数据库中存储数据的基本单位,由行(记录)和列(字段)组成。
text
┌─────────────────────────────────────────────────────────────┐
│ 表的结构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ users 表 │
│ ┌──────┬──────────┬─────────────────┬───────────────────┐│
│ │ id │ name │ email │ created_at ││
│ ├──────┼──────────┼─────────────────┼───────────────────┤│
│ │ 1 │ Alice │ alice@test.com │ 2026-03-29 10:00 ││
│ │ 2 │ Bob │ bob@test.com │ 2026-03-29 11:00 ││
│ │ 3 │ Carol │ carol@test.com │ 2026-03-29 12:00 ││
│ └──────┴──────────┴─────────────────┴───────────────────┘│
│ │
│ 列(字段) 行(记录) │
│ │
└─────────────────────────────────────────────────────────────┘
创建表 #
CREATE TABLE 基本语法 #
sql
CREATE TABLE table_name (
column1 data_type [column_constraints],
column2 data_type [column_constraints],
...,
[table_constraints]
);
创建简单表 #
sql
-- 创建用户表
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(50) NOT NULL,
email VARCHAR(100) UNIQUE,
age INTEGER,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 查看表结构
\d users
-- 输出:
-- Table "public.users"
-- Column | Type | Collation | Nullable | Default
-- -------------+-----------------------------+-----------+----------+-----------------------------------
-- id | integer | | not null | nextval('users_id_seq'::regclass)
-- username | character varying(50) | | not null |
-- email | character varying(100) | | |
-- age | integer | | |
-- is_active | boolean | | | true
-- created_at | timestamp without time zone | | | CURRENT_TIMESTAMP
-- Indexes:
-- "users_pkey" PRIMARY KEY, btree (id)
-- "users_email_key" UNIQUE CONSTRAINT, btree (email)
使用 IF NOT EXISTS #
sql
-- 如果表不存在则创建
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
name VARCHAR(100)
);
创建带注释的表 #
sql
-- 创建表
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
price DECIMAL(10, 2) NOT NULL,
description TEXT
);
-- 添加表注释
COMMENT ON TABLE products IS '商品信息表';
-- 添加列注释
COMMENT ON COLUMN products.id IS '商品ID,主键';
COMMENT ON COLUMN products.name IS '商品名称';
COMMENT ON COLUMN products.price IS '商品价格,单位:元';
COMMENT ON COLUMN products.description IS '商品描述';
约束类型 #
主键约束(PRIMARY KEY) #
sql
-- 单列主键
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100)
);
-- 等价于
CREATE TABLE users (
id SERIAL,
name VARCHAR(100),
PRIMARY KEY (id)
);
-- 复合主键
CREATE TABLE order_items (
order_id INTEGER,
product_id INTEGER,
quantity INTEGER,
PRIMARY KEY (order_id, product_id)
);
外键约束(FOREIGN KEY) #
sql
-- 创建主表
CREATE TABLE categories (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL
);
-- 创建从表,带外键
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
category_id INTEGER REFERENCES categories(id),
price DECIMAL(10, 2)
);
-- 完整的外键语法
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
category_id INTEGER,
price DECIMAL(10, 2),
CONSTRAINT fk_products_category
FOREIGN KEY (category_id)
REFERENCES categories(id)
ON DELETE CASCADE -- 删除主表记录时级联删除
ON UPDATE CASCADE -- 更新主表记录时级联更新
);
-- 外键引用行为
-- ON DELETE/UPDATE:
-- CASCADE - 级联操作
-- SET NULL - 设置为 NULL
-- SET DEFAULT - 设置为默认值
-- RESTRICT - 限制,不允许操作(默认)
-- NO ACTION - 同 RESTRICT
唯一约束(UNIQUE) #
sql
-- 列级唯一约束
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(50) UNIQUE,
email VARCHAR(100) UNIQUE
);
-- 表级唯一约束
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(50),
email VARCHAR(100),
CONSTRAINT uq_users_username UNIQUE (username),
CONSTRAINT uq_users_email UNIQUE (email)
);
-- 复合唯一约束
CREATE TABLE user_roles (
user_id INTEGER,
role_id INTEGER,
UNIQUE (user_id, role_id)
);
非空约束(NOT NULL) #
sql
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL,
phone VARCHAR(20) -- 可以为 NULL
);
检查约束(CHECK) #
sql
-- 列级检查约束
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
price DECIMAL(10, 2) CHECK (price > 0),
stock INTEGER CHECK (stock >= 0)
);
-- 表级检查约束
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
start_date DATE NOT NULL,
end_date DATE NOT NULL,
CONSTRAINT chk_orders_dates CHECK (end_date > start_date)
);
-- 多列检查约束
CREATE TABLE employees (
id SERIAL PRIMARY KEY,
salary DECIMAL(10, 2),
bonus DECIMAL(10, 2),
CONSTRAINT chk_employee_compensation CHECK (salary + bonus > 0)
);
默认值约束(DEFAULT) #
sql
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
status VARCHAR(20) DEFAULT 'active',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 使用函数作为默认值
CREATE TABLE sessions (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
token VARCHAR(255) DEFAULT md5(random()::TEXT),
expires_at TIMESTAMP DEFAULT (CURRENT_TIMESTAMP + INTERVAL '24 hours')
);
排除约束(EXCLUDE) #
sql
-- 排除约束确保某些列的组合不满足特定条件
-- 需要安装 btree_gist 扩展
CREATE EXTENSION IF NOT EXISTS btree_gist;
-- 确保同一会议室的时间不重叠
CREATE TABLE room_bookings (
id SERIAL PRIMARY KEY,
room_id INTEGER NOT NULL,
during TSRANGE NOT NULL,
EXCLUDE USING GIST (
room_id WITH =,
during WITH &&
)
);
-- 插入测试
INSERT INTO room_bookings (room_id, during) VALUES
(1, '[2026-03-29 10:00, 2026-03-29 12:00)');
-- 这条会失败,因为时间重叠
-- INSERT INTO room_bookings (room_id, during) VALUES
-- (1, '[2026-03-29 11:00, 2026-03-29 13:00)');
修改表 #
ALTER TABLE 概述 #
sql
-- ALTER TABLE 可以:
-- 1. 添加/删除列
-- 2. 修改列类型
-- 3. 添加/删除约束
-- 4. 重命名表/列
-- 5. 修改列默认值
添加列 #
sql
-- 添加单列
ALTER TABLE users ADD COLUMN phone VARCHAR(20);
-- 添加带约束的列
ALTER TABLE users ADD COLUMN age INTEGER CHECK (age >= 0);
-- 添加带默认值的列
ALTER TABLE users ADD COLUMN status VARCHAR(20) DEFAULT 'active';
-- 添加多列
ALTER TABLE users
ADD COLUMN address TEXT,
ADD COLUMN city VARCHAR(100);
删除列 #
sql
-- 删除列
ALTER TABLE users DROP COLUMN phone;
-- 如果列存在则删除
ALTER TABLE users DROP COLUMN IF EXISTS phone;
-- 强制删除(删除依赖对象)
ALTER TABLE users DROP COLUMN phone CASCADE;
修改列 #
sql
-- 修改列类型
ALTER TABLE users ALTER COLUMN phone TYPE VARCHAR(50);
-- 修改列类型并转换数据
ALTER TABLE users ALTER COLUMN phone TYPE VARCHAR(50)
USING phone::VARCHAR(50);
-- 修改列名
ALTER TABLE users RENAME COLUMN phone TO phone_number;
-- 设置默认值
ALTER TABLE users ALTER COLUMN status SET DEFAULT 'pending';
-- 删除默认值
ALTER TABLE users ALTER COLUMN status DROP DEFAULT;
-- 设置非空
ALTER TABLE users ALTER COLUMN name SET NOT NULL;
-- 删除非空约束
ALTER TABLE users ALTER COLUMN name DROP NOT NULL;
添加约束 #
sql
-- 添加主键
ALTER TABLE users ADD PRIMARY KEY (id);
-- 添加唯一约束
ALTER TABLE users ADD CONSTRAINT uq_users_email UNIQUE (email);
-- 添加外键
ALTER TABLE orders
ADD CONSTRAINT fk_orders_users
FOREIGN KEY (user_id) REFERENCES users(id);
-- 添加检查约束
ALTER TABLE products
ADD CONSTRAINT chk_products_price CHECK (price > 0);
删除约束 #
sql
-- 删除约束(需要知道约束名)
ALTER TABLE users DROP CONSTRAINT uq_users_email;
-- 查看约束名
SELECT conname, contype, pg_get_constraintdef(oid)
FROM pg_constraint
WHERE conrelid = 'users'::regclass;
-- 删除主键
ALTER TABLE users DROP CONSTRAINT users_pkey;
-- 删除外键
ALTER TABLE orders DROP CONSTRAINT fk_orders_users;
重命名表 #
sql
-- 重命名表
ALTER TABLE users RENAME TO app_users;
-- 重命名表和列
ALTER TABLE users RENAME TO app_users;
ALTER TABLE app_users RENAME COLUMN name TO username;
删除表 #
DROP TABLE #
sql
-- 删除表
DROP TABLE users;
-- 如果存在则删除
DROP TABLE IF EXISTS users;
-- 强制删除(删除依赖对象)
DROP TABLE users CASCADE;
-- 删除多个表
DROP TABLE users, orders, products;
TRUNCATE TABLE #
sql
-- 清空表数据(保留表结构)
TRUNCATE TABLE users;
-- 清空并重置自增序列
TRUNCATE TABLE users RESTART IDENTITY;
-- 清空多个表
TRUNCATE TABLE users, orders;
-- 级联清空(清空有外键引用的表)
TRUNCATE TABLE users CASCADE;
-- TRUNCATE vs DELETE
-- TRUNCATE: 更快,不触发触发器,重置序列
-- DELETE: 较慢,触发触发器,不重置序列
临时表 #
创建临时表 #
sql
-- 创建临时表(会话结束后自动删除)
CREATE TEMP TABLE temp_users AS
SELECT id, name FROM users WHERE status = 'active';
-- 创建临时表并指定结构
CREATE TEMP TABLE temp_orders (
id INTEGER,
total DECIMAL(10, 2)
);
-- 临时表只在当前会话可见
-- 会话结束后自动删除
临时表特性 #
sql
-- 临时表在会话结束时自动删除
-- 临时表默认在临时 schema 中
-- 可以创建同名临时表隐藏永久表
CREATE TABLE my_table (id INT); -- 永久表
CREATE TEMP TABLE my_table (id INT); -- 临时表(隐藏永久表)
-- 查看所有临时表
SELECT * FROM pg_tables WHERE schemaname = 'pg_temp_%';
表继承 #
创建继承表 #
sql
-- 父表
CREATE TABLE persons (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
birth_date DATE
);
-- 子表继承父表
CREATE TABLE employees (
employee_id VARCHAR(20),
hire_date DATE,
salary DECIMAL(10, 2)
) INHERITS (persons);
-- 子表包含父表的所有列
\d employees
-- Column | Type | Collation | Nullable | Default
-- ------------+-----------------------+-----------+----------+-----------------------------------
-- id | integer | | not null | nextval('persons_id_seq'::regclass)
-- name | character varying(100)| | |
-- birth_date | date | | |
-- employee_id| character varying(20) | | |
-- hire_date | date | | |
-- salary | numeric(10,2) | | |
继承表查询 #
sql
-- 查询父表(只返回父表数据)
SELECT * FROM ONLY persons;
-- 查询父表(返回父表和所有子表数据)
SELECT * FROM persons;
-- 查询子表
SELECT * FROM employees;
分区表 #
范围分区 #
sql
-- 创建分区表(父表)
CREATE TABLE orders (
id SERIAL,
order_date DATE NOT NULL,
customer_id INTEGER,
amount DECIMAL(10, 2)
) PARTITION BY RANGE (order_date);
-- 创建分区
CREATE TABLE orders_2026_01 PARTITION OF orders
FOR VALUES FROM ('2026-01-01') TO ('2026-02-01');
CREATE TABLE orders_2026_02 PARTITION OF orders
FOR VALUES FROM ('2026-02-01') TO ('2026-03-01');
CREATE TABLE orders_2026_03 PARTITION OF orders
FOR VALUES FROM ('2026-03-01') TO ('2026-04-01');
-- 创建默认分区
CREATE TABLE orders_default PARTITION OF orders DEFAULT;
-- 插入数据会自动路由到对应分区
INSERT INTO orders (order_date, customer_id, amount) VALUES
('2026-01-15', 1, 100.00),
('2026-02-20', 2, 200.00),
('2026-03-10', 3, 300.00);
列表分区 #
sql
-- 创建列表分区表
CREATE TABLE customers (
id SERIAL,
name VARCHAR(100),
region VARCHAR(20)
) PARTITION BY LIST (region);
-- 创建分区
CREATE TABLE customers_east PARTITION OF customers
FOR VALUES IN ('Beijing', 'Shanghai', 'Guangzhou');
CREATE TABLE customers_west PARTITION OF customers
FOR VALUES IN ('Chengdu', 'Chongqing', 'Xian');
CREATE TABLE customers_default PARTITION OF customers DEFAULT;
哈希分区 #
sql
-- 创建哈希分区表
CREATE TABLE logs (
id SERIAL,
message TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) PARTITION BY HASH (id);
-- 创建分区
CREATE TABLE logs_0 PARTITION OF logs
FOR VALUES WITH (MODULUS 4, REMAINDER 0);
CREATE TABLE logs_1 PARTITION OF logs
FOR VALUES WITH (MODULUS 4, REMAINDER 1);
CREATE TABLE logs_2 PARTITION OF logs
FOR VALUES WITH (MODULUS 4, REMAINDER 2);
CREATE TABLE logs_3 PARTITION OF logs
FOR VALUES WITH (MODULUS 4, REMAINDER 3);
查看表信息 #
使用 psql 命令 #
sql
-- 查看表结构
\d users
-- 查看详细表结构
\d+ users
-- 列出所有表
\dt
-- 列出所有表(包括系统表)
\dt+
-- 查看表索引
\di
-- 查看表约束
\dc
使用 SQL 查询 #
sql
-- 查看表结构
SELECT
column_name,
data_type,
character_maximum_length,
is_nullable,
column_default
FROM information_schema.columns
WHERE table_name = 'users'
ORDER BY ordinal_position;
-- 查看表约束
SELECT
tc.constraint_name,
tc.constraint_type,
kcu.column_name
FROM information_schema.table_constraints tc
JOIN information_schema.key_column_usage kcu
ON tc.constraint_name = kcu.constraint_name
WHERE tc.table_name = 'users';
-- 查看表大小
SELECT
pg_size_pretty(pg_total_relation_size('users')) AS total_size,
pg_size_pretty(pg_relation_size('users')) AS table_size,
pg_size_pretty(pg_total_relation_size('users') - pg_relation_size('users')) AS index_size;
-- 查看表统计信息
SELECT * FROM pg_stat_user_tables WHERE relname = 'users';
最佳实践 #
表设计原则 #
text
┌─────────────────────────────────────────────────────────────┐
│ 表设计原则 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 规范化设计 │
│ 避免数据冗余,合理使用外键 │
│ │
│ 2. 选择合适的数据类型 │
│ 不要过度使用 TEXT,选择合适的数值类型 │
│ │
│ 3. 添加适当的约束 │
│ NOT NULL、CHECK、外键保证数据完整性 │
│ │
│ 4. 合理使用索引 │
│ 主键自动创建索引,外键和常用查询列考虑索引 │
│ │
│ 5. 表和列命名规范 │
│ 小写、下划线分隔、见名知意 │
│ │
│ 6. 添加注释 │
│ 为表和重要列添加注释 │
│ │
└─────────────────────────────────────────────────────────────┘
命名规范 #
sql
-- 表名:小写,复数,下划线分隔
users, order_items, product_categories
-- 列名:小写,下划线分隔
user_name, created_at, is_active
-- 主键:id 或 表名_id
id, user_id, order_id
-- 外键:关联表名_id
category_id, user_id
-- 布尔列:is_xxx, has_xxx
is_active, is_deleted, has_permission
-- 时间列:xxx_at
created_at, updated_at, deleted_at
学习路径 #
text
基础阶段
├── 数据库操作
├── 表操作(本文)
├── 数据CRUD
└── 基础查询
下一步 #
掌握了表操作后,接下来学习 数据插入,开始向表中添加数据!
最后更新:2026-03-29