SQL 数据清洗与转换实践

3次阅读

where中NULL判断失效因null非值而是缺失标记,须用is null;trim/replace无法处理unicode控制符;类型转换失败在mysql严格模式下静默变null;update漏写精确where条件易误更新全表。

SQL 数据清洗与转换实践

WHERE 条件里写 NULL 判断会失效? 常见错误现象:WHERE column = NULL 返回空结果,哪怕表里明明有 NULL 值

SQL 里 NULL 不是值,而是“缺失标记”,不能用 =!= 比较。所有涉及 NULL 的等值判断都会返回 UNKNOWN,而 WHERE 只接受 TRUE

  • IS NULLIS NOT NULL 替代 = NULL
  • 聚合函数如 count(column) 自动跳过 NULL,但 COUNT(*) 不跳 —— 这常被误用来“查空行数”
  • 连接时 ON a.id = b.id 若任一为 NULL,该行直接不匹配,不是“匹配失败”,是“不参与连接”

字符串清洗:TRIM 和 REPLACE 够用吗? 使用场景:处理用户输入、CSV 导入、爬虫数据中混杂的空格、不可见字符(如 tr、零宽空格)

TRIM() 只去首尾空格(默认空格,可指定字符),REPLACE() 能换指定子串,但两者都对 Unicode 控制符、全角空格、bom 头无能为力。

  • postgresql 可用 REGEXP_REPLACE(col, '[u200B-u200DuFEFF]+', '', 'g') 清零宽字符
  • MySQL 8.0+ 支持 REGEXP_REPLACE();老版本只能靠应用层或自定义函数
  • 别用 REPLACE(col, ' ', '') 清空格——它会把字段内正常空格也干掉,破坏语义

类型转换失败导致整列变 NULL? 错误现象:CAST(age_str AS Integer) 后整列变 NULL,但只有一两行是非法值

多数数据库(如 PostgreSQL、SQL Server)在类型转换失败时默认抛错;但 MySQL 在非严格模式下会静默转成 0NULL,且不报任何提示,极易掩盖脏数据。

  • PostgreSQL 推荐用 col::INTEGER + NULLIF() 组合:例如 NULLIF(TRIM(age_str), '')::INTEGER
  • MySQL 开启严格模式(STRICT_TRANS_TABLES)让转换失败立刻报错,而不是吞掉异常
  • 避免用 CONVERT()CAST() 直接套原始字段,先用 REGEXP_LIKE()(MySQL 8.0+/PostgreSQL)筛出合法格式再转

UPDATE 时 WHERE 条件漏写主键,全表被改? 真实踩坑场景:开发环境跑完 UPDATE user SET status = 'active',发现 20 万用户全激活了

没有 WHEREUPDATE / delete 是高危操作,但更危险的是 WHERE 写得不精确,比如用 WHERE name = '张三' —— 名字重复太常见。

  • 执行前先用 select COUNT(*) 验证条件命中行数,尤其涉及 JOIN 或子查询时
  • 在事务里操作:BEGIN; UPDATE ...; SELECT ROW_COUNT(); ROLLBACK;(MySQL)或 SELECT pg_affected_rows()(PostgreSQL)
  • 别依赖 ide 的“安全更新模式”,它只拦没 WHERE,不拦弱条件;真正安全的是主键/唯一索引字段 + 明确值

实际清洗时最麻烦的不是语法,是搞不清原始数据到底“缺什么”——比如一个 phone 字段,你以为只是空格多,结果发现混着 +8686-(010)138****1234 四种格式,还夹着“暂无”“不详”“/”。这种得先 GROUP BY 看分布,再分策略处理,没法一条 SQL 搞定。

text=ZqhQzanResources