布尔值怎么存怎么比
PostgreSQL 有原生 boolean 类型,取值只有 true、false、NULL,运算遵循三值逻辑。MySQL 没有独立的布尔类型,TRUE 与 FALSE 只是数字 1 与 0 的别名,任何布尔表达式的结果也是 0 或 1,标志列通常用 tinyint(1) 承载。这个差异直接影响写法:MySQL 里可以把标志列直接当条件用,PostgreSQL 里只有列本身就是 boolean 类型才能这样写,写成与数字比较会直接报类型错误。所以同一套应用代码在两种数据库上跑,条件表达式往往要分别写。
基本信息
| 适用平台 | MySQL 8.0 / PostgreSQL 12 及以上 |
|---|---|
| MySQL 表示法 | 没有原生布尔类型,TRUE 与 FALSE 等价数字 1 与 0,列型常用 tinyint(1) |
| PostgreSQL 表示法 | 原生 boolean 列,只接受 true、false、NULL 三个取值 |
| 条件书写 | MySQL 可直接把标志列写成条件;PostgreSQL 要求该列本身是布尔类型 |
| 三值逻辑 | 两库的 NULL 参与比较结果都是 UNKNOWN,不会自动当成假 |
典型使用场景
- 软删除标志列:查询时按标志过滤,只取未删除的数据
- 功能开关配置表:记录某个功能是否启用、是否参与灰度
- 对外接口返回需要真正的 true 与 false,而不是数字 1 和 0
- 从 MySQL 迁移到 PostgreSQL 时把 tinyint(1) 改成 boolean,并同步改写查询条件
- 统计报表按标志分组计数,需要确认 NULL 行算在哪一类
- 给标志列建索引前评估区分度,绝大多数行同一取值时收益有限
两库写法对照
两库写法对照
-- MySQL:TRUE 与 FALSE 只是 1 与 0 的别名
SELECT 1 = 1 AS r; -- 结果是数字 1,不是 true
SELECT TRUE, FALSE; -- 结果是 1, 0
SELECT * FROM t WHERE flag = 1; -- 与数字比较是常规写法
SELECT * FROM t WHERE flag; -- 标志列可直接当条件,非零即命中
-- PostgreSQL:布尔类型专属写法
SELECT 1 = 1; -- 结果是 true
SELECT true AND false; -- 结果是 false
SELECT * FROM t WHERE flag; -- 要求 flag 是 boolean 列
SELECT * FROM t WHERE flag = true; -- 显式比较,可读性更好
SELECT * FROM t WHERE flag IS TRUE; -- 只在确实为 true 时命中布尔列在各层表现
| 观察位置 | MySQL 表现 | PostgreSQL 表现 |
|---|---|---|
| 列类型 | tinyint(1),可以存 0、1 与 NULL | boolean,只接受 true、false 与 NULL |
| 比较运算 | 与数字 1 比较、与 TRUE 比较都可以 | 与数字比较直接报类型错误 |
| 结果输出 | 输出数字 1 与 0 | 输出 t 与 f,多数驱动可转成真值 |
| 聚合求和 | 对标志列求和直接得到命中行数 | 布尔列不能求和,要改成条件计数 |
| 索引选择 | 区分度低时单列索引收益有限 | 同样因区分度低常被优化器放弃 |
三值逻辑是这块最常见的误解:标志列为 NULL 的行,在「标志为真」与「标志为假」两个条件里都不命中。做统计口径时要把 NULL 单独归一类,否则两边的数字相加对不上总行数,排查时容易怀疑数据丢了。
PostgreSQL 里按布尔列计数可以用带过滤的聚合,例如统计为真的行数写成 COUNT(*) FILTER (WHERE flag),比把布尔强转成整数可读性更好,也避免多余的隐式转换。