1. 类型
数据库中的每一列都必须声明类型。类型告诉 PostgreSQL 这一列允许保存什么数据、怎样比较、怎样排序,以及可以执行哪些运算。
例如,任务标题适合使用文本,优先级适合使用整数,截止时间适合使用带时区的时间:
1CREATE TABLE task_type_example (2title text,3priority smallint,4completed boolean,5due_at timestamptz6);
Python 也有 str、int、bool 等类型,但 Python 类型和数据库类型并不是同一个系统。Python 对象需要经过数据库驱动转换,才能成为 PostgreSQL 能保存的值:
| Python | PostgreSQL | 说明 |
|---|---|---|
str | text、varchar | 标题、描述等字符串 |
int | smallint、integer、bigint、numeric | 实际列类型决定最终可接受的范围 |
float | double precision | 近似浮点数 |
Decimal | numeric | 金额等精确小数 |
bool | boolean | True 和 False |
date | date | 只包含日期 |
不带 tzinfo 的 datetime | timestamp | 不表示确定的全球时间点 |
带 tzinfo 的 datetime | timestamptz | 表示确定的时间点 |
timedelta | interval | 时间间隔 |
UUID | uuid | UUID 标识符 |
bytes、bytearray、memoryview | bytea | 二进制数据 |
list | PostgreSQL 数组 | Psycopg 默认把同类型列表适配为数组 |
使用 Json、Jsonb 包装的对象 | json、jsonb | JSON 对象、数组或标量 |
2. 基础类型
数字
PostgreSQL 的数字类型可以分为整数、精确小数和近似浮点数。它们在存储空间、取值范围和计算精度上各不相同:
| 类型 | 空间 | 范围或精度 | 常见场景 |
|---|---|---|---|
smallint | 2 字节 | -32768 到 32767 | 范围明确且较小的整数,例如优先级、评分 |
integer | 4 字节 | -2147483648 到 2147483647 | 普通计数和编号,例如数量、页码 |
bigint | 8 字节 | -9223372036854775808 到 9223372036854775807 | 可能超过 integer 范围的编号或计数,例如大型系统的主键 |
numeric(p, s) / decimal(p, s) | 可变 | 精确十进制,p 为总位数,s 为小数位数 | 金额、税率、需要精确舍入的业务小数 |
real | 4 字节 | 约 6 位十进制有效数字,近似值 | 对精度要求不高的测量值、模拟数据 |
double precision | 8 字节 | 约 15 位十进制有效数字,近似值 | 科学计算、统计分析、允许误差的坐标或比例 |
不要因为 bigint 范围更大就无条件使用它,也不要为了节省几个字节把所有数字都设为 smallint。integer 在范围、空间和性能之间比较均衡。只有已经知道数据规模会超过它的上限时,才需要选择 bigint。
小数需要区分精确值和近似值:
1CREATE TABLE prices (2amount numeric(12, 2),3confidence double precision4);
numeric(12, 2) 的精度是 12,标度是 2,也就是总共最多 12 位数字,其中小数部分保留 2 位,整数部分最多 10 位。写入更多小数位时,PostgreSQL 会先舍入到 2 位;如果舍入后的整数部分超过 10 位,则会报错。decimal 与 numeric 在 PostgreSQL 中是等价类型。
real 和 double precision 是浮点数,适合统计、测量等允许微小误差的场景。它们的计算通常比 numeric 更快,但保存的是二进制近似值,直接使用等号比较计算结果也可能得到意外结果。
金额不要使用浮点数。0.1 + 0.2 一类计算可能受到二进制浮点表示影响,而 numeric 会按十进制精确保存和计算。
PostgreSQL 还提供 money 类型,但它的显示格式和小数精度会受到区域设置影响,跨环境迁移和计算时更容易产生困惑。业务金额通常使用 numeric(p, s) 更清晰。
布尔
boolean 可以保存 true、false,如果列允许为空,还可以保存 NULL。因此,可空布尔列实际表达了三种状态。只有业务确实存在“未知”状态时才应该允许它为空,否则应配合 NOT NULL 和合理的默认值使用。
1CREATE TABLE boolean_example (2id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,3is_completed boolean NOT NULL DEFAULT false,4is_archived boolean5);
is_completed 是典型的二态字段:每一行都必须明确表示是否完成,省略该列时默认为 false。is_archived 没有设置 NOT NULL,因此还可以用 NULL 表示“尚未确定是否归档”。是否允许这种第三种状态,应由业务含义决定。