where中= NULL失效,因null是缺失标记,等值比较结果为unknown;须用is null;group by非聚合字段需显式分组或聚合;清洗手机号应优先用regexp_replace剔除非数字字符。

WHERE 条件里用 NULL 判断会失效?用 IS NULL 而不是 = NULL
sql 里 NULL 不是值,而是“缺失”的标记,所以任何和 NULL 的等值比较(比如 = NULL、!= NULL)结果都是 UNKNOWN,被 WHERE 当作假——查不到数据,但也不报错,容易误以为数据不存在。
-
WHERE col = NULL→ 永远不匹配,哪怕该列全是NULL - 正确写法是
WHERE col IS NULL或WHERE col IS NOT NULL - 如果要统一处理空值再比较,可配合
COALESCE(col, '')或NULLIF(col, ''),但要注意类型隐式转换风险(比如把数字转成字符串后做=)
GROUP BY 后字段必须在 select 中出现或被聚合?不是所有数据库都强制
mysql 默认允许 SELECT a, b FROM t GROUP BY a(b 未聚合也未分组),但 postgresql、SQL Server、标准 SQL 都会报错:column "b" must appear in the GROUP BY clause or be used in an aggregate function。这常导致迁移或跨库查询时突然失败。
- 安全写法:所有非聚合字段都放进
GROUP BY,或明确用聚合函数包裹,如MAX(b)、STRING_AGG(b, ',') - MySQL 8.0+ 开启
ONLY_FULL_GROUP_BY模式后行为与其他数据库一致,建议开发环境默认启用 - 别依赖
SELECT *+GROUP BY——字段增减会直接让语句不可控
清洗手机号、身份证号这类文本字段,TRIM() 和 REPLACE() 不够,得用 REGEXP_REPLACE()
真实数据里常见空格、换行、中文括号、短横线混在号码中,比如 "138- 0013 8000n" 或 "(138)00138000"。TRIM() 只能去首尾,REPLACE() 写一堆嵌套可读性差且漏情况。
- PostgreSQL / MySQL 8.0+ 支持
REGEXP_REPLACE(col, '[^0-9]', '', 'g'),一次性剔除非数字字符 - 注意:MySQL 5.7 不支持
g标志,需用循环或应用层处理;sqlite 默认无正则,得加载扩展或改用replace()多层嵌套(不推荐) - 清洗后建议加长度校验,比如
Length(cleaned_phone) = 11,避免“13800138000123”这种超长脏数据混入
分析时用 LEFT JOIN 却没查到右表数据?检查 ON 条件里的空值和类型隐式转换
LEFT JOIN 本应保留左表全部记录,但若右表关联字段含 NULL 或类型不一致(比如左表是 VARCHAR 的 ID,右表是 int),ON 条件永远不成立,右表字段全为 NULL,看起来像“没连上”。
- 先确认右表关联字段是否有
NULL:SELECT count(*) FROM right_table WHERE join_col IS NULL - 检查字段类型是否一致:
SELECT pg_typeof(join_col) FROM right_table LIMIT 1(PostgreSQL)或DESCRIBE right_table(MySQL) - 避免隐式转换:显式转类型,如
ON CAST(l.id AS TEXT) = r.str_id,比依赖数据库自动转换更可靠
空值和类型问题在清洗阶段不暴露,一到关联分析就断链,而且错误安静——没报错,只少数据。