PostgreSQL 数据类型
PostgreSQL 数据类型全解析
PostgreSQL 的数据类型极其丰富,不仅支持标准 SQL 类型,还提供 数组、JSON、范围、几何、UUID、自定义类型 等高级特性。
本文按 分类 + 用法 + 最佳实践 全面讲解。
一、数字类型
| 类型 | 存储大小 | 范围 | 推荐场景 |
|---|---|---|---|
SMALLINT | 2 字节 | -32,768 ~ 32,767 | 小整数(如状态码、评分 1~5) |
INTEGER / INT | 4 字节 | -2.1B ~ 2.1B | 通用整数(主键、计数) |
BIGINT | 8 字节 | -9.2E18 ~ 9.2E18 | 大计数、雪花 ID |
SERIAL | 4 字节 | 1 ~ 2.1B | 自增 ID(int) |
BIGSERIAL | 8 字节 | 1 ~ 9.2E18 | 大表自增 ID |
NUMERIC(p,s) | 可变 | 精确到小数点后 s 位 | 金融、金额(推荐) |
DECIMAL(p,s) | 同上 | 同 NUMERIC | 同上 |
REAL | 4 字节 | 6 位小数精度 | 浮点科学计算 |
DOUBLE PRECISION | 8 字节 | 15 位小数精度 | 科学计算、坐标 |
注意:不要用
FLOAT存金额!用NUMERIC(19,4)或MONEY(但MONEY有时区问题,不推荐)
CREATE TABLE orders (
id BIGSERIAL PRIMARY KEY,
quantity INTEGER NOT NULL CHECK (quantity > 0),
price NUMERIC(10,2) NOT NULL, -- 最大 8 位整数 + 2 位小数
total NUMERIC(12,2) GENERATED ALWAYS AS (quantity * price) STORED
);
二、字符类型
| 类型 | 存储 | 说明 | 推荐 |
|---|---|---|---|
CHAR(n) | 固定 n 字节 | 不足补空格 | 极少用 |
VARCHAR(n) | 可变,最多 n | 通用文本 | 推荐 |
TEXT | 可变,无限(1GB) | 无长度限制 | 强烈推荐 |
CITEXT | 可变 | 忽略大小写(需扩展) | 邮箱、用户名 |
-- 推荐写法
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
email CITEXT UNIQUE, -- 需 CREATE EXTENSION citext;
bio TEXT
);
三、布尔类型
| 类型 | 存储 | 值 |
|---|---|---|
BOOLEAN | 1 字节 | TRUE / FALSE / NULL |
is_active BOOLEAN DEFAULT true,
is_verified BOOLEAN NOT NULL DEFAULT false
四、时间日期类型
| 类型 | 存储 | 说明 | 推荐 |
|---|---|---|---|
DATE | 4 字节 | 日期(无时间) | 生日 |
TIME | 8 字节 | 时间(无日期) | 很少单独用 |
TIMETZ | 12 字节 | 带时区时间 | 少用 |
TIMESTAMP | 8 字节 | 日期+时间(无时区) | 旧系统 |
TIMESTAMPTZ | 8 字节 | 带时区时间戳 | 强烈推荐 |
INTERVAL | 16 字节 | 时间间隔 | 超时、统计 |
CREATE TABLE events (
id SERIAL PRIMARY KEY,
name TEXT,
created_at TIMESTAMPTZ DEFAULT now(), -- 推荐
updated_at TIMESTAMPTZ DEFAULT now(),
event_date DATE,
duration INTERVAL DEFAULT '1 hour'
);
最佳实践:所有时间戳一律用
TIMESTAMPTZ,自动处理时区。
五、JSON 类型(PostgreSQL 杀手级特性)
| 类型 | 说明 | 推荐 |
|---|---|---|
JSON | 存储原始 JSON 文本 | 仅用于存储 |
JSONB | 二进制格式,支持索引、操作符 | 强烈推荐 |
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name TEXT,
specs JSONB
);
-- 插入
INSERT INTO products (name, specs) VALUES ('Phone', '{
"brand": "Apple",
"price": 999,
"features": ["5G", "OLED"],
"in_stock": true
}');
-- 查询
SELECT name, specs->>'brand' AS brand FROM products;
SELECT * FROM products WHERE specs @> '{"in_stock": true}';
SELECT * FROM products WHERE specs->'features' ? '5G';
-- 索引
CREATE INDEX idx_products_specs ON products USING GIN (specs);
六、数组类型(Array)
CREATE TABLE articles (
id SERIAL PRIMARY KEY,
title TEXT,
tags TEXT[], -- 文本数组
scores INTEGER[] DEFAULT '{}'
);
-- 插入
INSERT INTO articles (title, tags) VALUES ('PG 教程', '{"database","sql","json"}');
-- 查询
SELECT * FROM articles WHERE tags @> ARRAY['sql'];
SELECT title, tags[1] AS first_tag FROM articles;
-- 更新
UPDATE articles SET tags = tags || 'new' WHERE id = 1;
UPDATE articles SET tags = array_remove(tags, 'old') WHERE id = 1;
-- 索引
CREATE INDEX idx_articles_tags ON articles USING GIN (tags);
七、UUID 类型
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE TABLE sessions (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id INTEGER,
expires_at TIMESTAMPTZ
);
优点:分布式唯一、无序插入性能好
缺点:16 字节,比BIGINT大
八、网络地址类型
| 类型 | 说明 |
|---|---|
INET | IPv4/IPv6 地址 |
CIDR | IP 网段 |
MACADDR | MAC 地址 |
ip_address INET NOT NULL,
network CIDR
九、范围类型(Range)
CREATE EXTENSION IF NOT EXISTS int4range;
CREATE TABLE reservations (
id SERIAL PRIMARY KEY,
room_id INTEGER,
during TSRANGE NOT NULL, -- 时间范围
EXCLUDE USING GIST (room_id WITH =, during WITH &&)
);
-- 插入
INSERT INTO reservations (room_id, during)
VALUES (101, '[2025-11-03 14:00, 2025-11-03 16:00)');
十、货币类型(慎用)
price MONEY
不推荐:有本地化问题(如 $ vs ¥),精度不一致。
推荐:用NUMERIC(19,4)+ 应用层格式化。
十一、几何类型(需 PostGIS)
CREATE EXTENSION postgis;
location GEOMETRY(POINT, 4326), -- WGS84 经纬度
path GEOMETRY(LINESTRING, 4326)
十二、自定义类型(Composite Type)
CREATE TYPE address AS (
city TEXT,
street TEXT,
zip_code VARCHAR(10)
);
CREATE TABLE companies (
id SERIAL PRIMARY KEY,
name TEXT,
address address
);
-- 插入
INSERT INTO companies (name, address)
VALUES ('xAI', ROW('Beijing', 'Zhongguancun', '100000'));
十三、枚举类型(Enum)
CREATE TYPE mood AS ENUM ('happy', 'sad', 'angry');
CREATE TABLE daily_log (
id SERIAL PRIMARY KEY,
feeling mood NOT NULL
);
INSERT INTO daily_log (feeling) VALUES ('happy');
-- ALTER TYPE mood ADD VALUE 'excited'; -- 需在末尾添加
十四、序列(Sequence)
CREATE SEQUENCE user_id_seq START 1000 INCREMENT 2;
CREATE TABLE users (
id INTEGER DEFAULT nextval('user_id_seq') PRIMARY KEY
);
SERIAL内部就是序列,推荐使用SERIAL。
十五、类型转换(CAST)
-- 显式
SELECT '123'::INTEGER;
SELECT CAST('2025-11-03' AS DATE);
-- 隐式(谨慎)
SELECT 100 + '50'; -- 自动转成 150
十六、类型选择最佳实践(Checklist)
| 场景 | 推荐类型 |
|---|---|
| 主键 | BIGSERIAL 或 UUID |
| 用户名 | VARCHAR(50) 或 CITEXT |
| 邮箱 | CITEXT |
| 描述 | TEXT |
| 金额 | NUMERIC(19,4) |
| 时间 | TIMESTAMPTZ |
| 状态 | BOOLEAN 或 SMALLINT |
| 标签 | TEXT[] + GIN 索引 |
| 配置 | JSONB + GIN 索引 |
| IP 地址 | INET |
十七、查看类型信息(psql 命令)
\d tablename -- 查看表结构
\dt+ -- 查看表大小
SELECT typname, typlen FROM pg_type WHERE typname = 'int4';
十八、常见错误
| 错误 | 正确做法 |
|---|---|
VARCHAR 无长度 | 用 TEXT |
用 FLOAT 存钱 | 用 NUMERIC |
时间用 VARCHAR | 用 TIMESTAMPTZ |
| 数组不用索引 | 加 GIN 索引 |
总结:一图记住核心类型
整数 → INTEGER / BIGSERIAL
文本 → TEXT
邮箱 → CITEXT
时间 → TIMESTAMPTZ
金额 → NUMERIC(19,4)
配置 → JSONB
标签 → TEXT[]
唯一ID → UUID
状态 → BOOLEAN
现在就动手:
创建一个用户表,包含 id(BIGSERIAL)、username(CITEXT)、profile(JSONB)、tags(TEXT[])、created_at(TIMESTAMPTZ),插入 3 条数据,然后用 JSON 查询出 profile.level > 5 的用户。
需要我生成:
- 完整建表示例(含所有类型)?回复
建表示例 - JSONB vs 关系表性能对比?回复
性能对比 - 自动生成测试数据的 SQL?回复
测试数据
随时告诉我!