PostgreSQL 9.4布尔类型计数异常求助(Ubuntu 16.04环境)
嘿,我来帮你拆解这个问题——你遇到的计数不匹配情况,在PostgreSQL里其实是个容易踩的小坑,核心原因是布尔字段存在NULL值。
为什么总和对不上?
PostgreSQL的布尔类型不像有些数据库只有true和false两种状态,它还支持NULL(空值)。你现在的查询只统计了deleted = true的400条记录,但没考虑另外两种情况:deleted = false和deleted IS NULL。
总记录数9000是包含所有状态的,但你用SELECT count(*) from table where deleted;(等价于deleted = true)只拿到了true的数量,而删除记录数的查询如果只查deleted = false,结果肯定会和9000-400有差值,差值就是那些deleted为NULL的记录数。
至于为什么会有NULL值?哪怕你设置了默认值false,如果插入数据时主动给deleted赋了NULL,或者有些老数据在你设置默认值之前就已经存在NULL,都会导致这种情况——默认值只有在插入时不指定该字段的情况下才会生效,主动插入NULL的话默认值不会覆盖。
一步步解决问题
确认NULL值的存在
先跑这条SQL验证一下,看看是不是真的有NULL记录:SELECT count(*) FROM table WHERE deleted IS NULL;把这个结果加上400(true的数量),再加上
SELECT count(*) FROM table WHERE deleted = false;的结果,肯定等于总记录数9000。修复现有数据
如果NULL值是不合理的(你希望deleted只有true/false两种状态),把所有NULL更新为默认的false:UPDATE table SET deleted = false WHERE deleted IS NULL;执行完别忘了提交事务:
COMMIT;杜绝未来再出现NULL
为了防止以后再踩这个坑,修改表结构,把deleted字段设置为不允许为空:ALTER TABLE table ALTER COLUMN deleted SET NOT NULL;这样以后插入或更新数据时,就不能给deleted赋NULL值了,彻底锁死字段的状态范围。
更清晰的计数查询方式
以后要统计各状态数量的话,推荐用CASE语句一次性查全,一目了然:SELECT COUNT(*) AS total_records, COUNT(CASE WHEN deleted = true THEN 1 END) AS deleted_count, COUNT(CASE WHEN deleted = false THEN 1 END) AS active_count, COUNT(CASE WHEN deleted IS NULL THEN 1 END) AS null_count FROM table;
内容的提问来源于stack exchange,提问作者Hearen

