4 minutes
建表与数据类型
数据类型概览
PostgreSQL 支持丰富的数据类型,是 SQL 标准实现最全面的数据库之一。
数值类型
-- 整数类型
SMALLINT -- 2字节,范围 -32768 ~ 32767
INTEGER -- 4字节,范围 -21亿 ~ 21亿
BIGINT -- 8字节,范围超大
-- 精确小数
NUMERIC(10,2) -- 总共10位,小数点后2位,精确计算
DECIMAL(10,2) -- NUMERIC 的别名
-- 浮点类型
REAL -- 4字节,6位十进制精度
DOUBLE PRECISION -- 8字节,15位十进制精度
-- 自增类型
SMALLSERIAL -- 2字节自增
SERIAL -- 4字节自增(常用)
BIGSERIAL -- 8字节自增
字符串类型
CHAR(n) -- 定长字符串,不足补空格
VARCHAR(n) -- 变长字符串,有长度限制(最常用)
TEXT -- 不限长度字符串(无性能损失)
经验:不要被 CHAR 的"性能优势"迷惑。在 PostgreSQL 中,VARCHAR 和 TEXT 几乎没有性能差异。大多数场景直接使用 TEXT 最省心。如果需要限制长度,用
VARCHAR(n)。
时间/日期类型
DATE -- 日期(年月日)
TIME -- 时间(时分秒,可带时区)
TIMESTAMP -- 日期+时间(不带时区)
TIMESTAMPTZ -- 日期+时间(带时区)
INTERVAL -- 时间间隔(1 day '3 hours')
⚠️ 重要建议:数据库统一存储 UTC 时间,在前端展示时转换为用户本地时区。用 TIMESTAMPTZ 可以保留时区信息,但最佳实践是存入 UTC + 前端转换。
布尔类型
BOOLEAN -- TRUE / FALSE / NULL
-- 输入时也支持:'yes'/'no', '1'/'0', 't'/'f'
JSON 类型
JSON -- 文本格式的 JSON(保留格式,含空格/缩进)
JSONB -- 二进制格式(去除空格,可建索引,处理更快)
绝大多数场景应该使用 JSONB。
建表语法
完整建表示例
-- 创建 schema(命名空间)
CREATE SCHEMA IF NOT EXISTS school;
-- 创建一张完整的用户表
CREATE TABLE school.students (
id SERIAL PRIMARY KEY,
student_no VARCHAR(20) UNIQUE NOT NULL, -- 学号,唯一约束
name VARCHAR(50) NOT NULL,
gender CHAR(1) CHECK (gender IN ('M', 'F', 'O')), -- 检查约束
birth_date DATE,
email VARCHAR(200) UNIQUE,
phone VARCHAR(20),
address TEXT,
enrollment_date DATE DEFAULT CURRENT_DATE,
status VARCHAR(10) DEFAULT 'active' CHECK (status IN ('active', 'graduated', 'suspended')),
gpa NUMERIC(3,2) DEFAULT 0.00 CHECK (gpa >= 0.00 AND gpa <= 4.00),
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- 查看表结构
\d school.students
约束类型
PostgreSQL 支持以下约束:
-- 1. NOT NULL — 不能为空
name VARCHAR(100) NOT NULL
-- 2. UNIQUE — 唯一
email VARCHAR(200) UNIQUE
-- 3. PRIMARY KEY — 主键(NOT NULL + UNIQUE)
id SERIAL PRIMARY KEY
-- 4. CHECK — 条件检查
price NUMERIC(10,2) CHECK (price > 0)
age INTEGER CHECK (age >= 0 AND age <= 150)
-- 5. DEFAULT — 默认值
created_at TIMESTAMPTZ DEFAULT NOW()
约束命名(推荐)
CREATE TABLE products (
product_id SERIAL,
product_name VARCHAR(100) NOT NULL,
price NUMERIC(10,2),
category VARCHAR(50),
stock INTEGER DEFAULT 0,
CONSTRAINT pk_products PRIMARY KEY (product_id),
CONSTRAINT uq_products_name UNIQUE (product_name),
CONSTRAINT ck_products_price CHECK (price > 0),
CONSTRAINT ck_products_stock CHECK (stock >= 0)
);
有命名约束的好处:
- 报错信息清晰:
violates check constraint "ck_products_price" - 后续修改方便:
ALTER TABLE ... DROP CONSTRAINT ck_products_price;
修改表
-- 添加列
ALTER TABLE students ADD COLUMN wechat VARCHAR(50);
-- 删除列
ALTER TABLE students DROP COLUMN wechat;
-- 修改列类型
ALTER TABLE students ALTER COLUMN grade TYPE VARCHAR(10);
-- 设置默认值
ALTER TABLE students ALTER COLUMN grade SET DEFAULT 'freshman';
-- 添加约束
ALTER TABLE students ADD CONSTRAINT ck_students_age CHECK (age >= 0);
-- 删除约束
ALTER TABLE students DROP CONSTRAINT ck_students_age;
-- 重命名列
ALTER TABLE students RENAME COLUMN grade TO class_level;
-- 重命名表
ALTER TABLE students RENAME TO scholar;
Schema 管理
-- 创建 schema(类似命名空间/目录)
CREATE SCHEMA sales;
CREATE SCHEMA hr;
-- 在 schema 中创建表
CREATE TABLE sales.orders (id SERIAL PRIMARY KEY, ...);
CREATE TABLE hr.employees (id SERIAL PRIMARY KEY, ...);
-- 查看所有 schema
\dn
-- 设置搜索路径(简化访问)
SET search_path TO sales, hr, public;
实战:创建一个电商数据库的初始表
-- 创建使用数据库
CREATE DATABASE ecommerce;
\c ecommerce
-- 用户表
CREATE TABLE users (
user_id SERIAL PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(200) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
full_name VARCHAR(100),
phone VARCHAR(20),
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- 商品分类表
CREATE TABLE categories (
category_id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
parent_id INTEGER REFERENCES categories(category_id),
description TEXT
);
-- 商品表
CREATE TABLE products (
product_id SERIAL PRIMARY KEY,
category_id INTEGER REFERENCES categories(category_id),
name VARCHAR(200) NOT NULL,
description TEXT,
price NUMERIC(10,2) NOT NULL CHECK (price > 0),
stock INTEGER DEFAULT 0 CHECK (stock >= 0),
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- 订单表(先建,供订单项引用)
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES users(user_id),
status VARCHAR(20) DEFAULT 'pending'
CHECK (status IN ('pending', 'paid', 'shipped', 'delivered', 'cancelled')),
total_amount NUMERIC(12,2) NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- 订单项表(多对多关联表)
CREATE TABLE order_items (
order_id INTEGER REFERENCES orders(order_id),
product_id INTEGER REFERENCES products(product_id),
quantity INTEGER NOT NULL CHECK (quantity > 0),
unit_price NUMERIC(10,2) NOT NULL,
PRIMARY KEY (order_id, product_id)
);
数据类型选择原则
- 能用 INT 不用 BIGINT:4 字节 vs 8 字节,百万行就省 4MB
- 金额用 NUMERIC,不用 FLOAT:浮点数的精度问题会导致金额计算出错
- JSONB > JSON:JSONB 支持索引和高效操作
- TIMESTAMPTZ > TIMESTAMP:时区信息避免混淆
- TEXT 足够就用 TEXT:不需要长度限制时,TEXT 就是最好的选择
- 用 SERIAL/BIGSERIAL 而非手动管理自增
小结
本文详细介绍了 PostgreSQL 丰富的数据类型体系,以及建表、修改表、约束管理等核心 DDL 操作。良好的表设计是高效查询的基础,选择合适的数据类型不仅是规范问题,更是性能问题。
下一步,我们将学习如何用 SELECT 查询和过滤数据。
Summary: 数据类型、建表语法、约束与电商表设计实战。