MySQL 报错:ERROR 1048 (23000): Column ‘name’ cannot be null 实战排查

13次阅读
没有评论

背景

开发中经常遇到 INSERT ... SELECT 批量导入数据的场景,今天在同步团队创始人数据到 team_member 成员表时,遇到了经典的非空约束报错。

原始 SQL:

insert into team_member(team_id,team_invite_id,name,user_id,user_phone,type,work_type,gender,role,state,status,campus_id,college_id) 
select team.id,0,user.name,user.id,user.phone,1,1,user.gender,'创始人',0,1,user.campus,college_id 
from team left join user on team.user_id=user.id;

执行直接报错:

ERROR 1048 (23000): Column ‘name’ cannot be null

报错根因分析

team_member 表的 name 字段设置了非空约束(NOT NULL),不允许存入 NULL。

SQL 里用的是 team LEFT JOIN user:

  • 左连接逻辑:保留左表 team 的全部记录;
  • 如果某一条团队记录的 team.user_id 在 user 表找不到匹配用户,user 表所有字段都会变成 NULL,包含 user.name;
  • 最后把子查询得到的 NULL 塞进 team_member.name,触发数据库非空校验报错。

补充:LEFT JOIN 是坑点来源,很多人写批量同步 SQL 时忽略 “关联不到主表” 的脏数据。

另外还有一个隐藏隐患:college_id 没有加表别名,存在字段歧义,MySQL 自动推断表,很容易拿到错误的值。

三种解决方案,按需选择

方案 1:只保留关联成功的数据(业务最推荐)

业务含义:找不到对应用户的团队,不生成成员记录,直接把 LEFT JOIN 换成 INNER JOIN,或者增加 WHERE user.id IS NOT NULL 过滤。

写法 A(INNER JOIN)

insert into team_member(team_id,team_invite_id,name,user_id,user_phone,type,work_type,gender,role,state,status,campus_id,college_id) 
select team.id,0,user.name,user.id,user.phone,1,1,user.gender,'创始人',0,1,user.campus,team.college_id 
from team 
INNER JOIN user on team.user_id=user.id;

写法 B(LEFT JOIN + WHERE 过滤)

insert into team_member(team_id,team_invite_id,name,user_id,user_phone,type,work_type,gender,role,state,status,campus_id,college_id) 
select team.id,0,user.name,user.id,user.phone,1,1,user.gender,'创始人',0,1,user.campus,team.college_id 
from team 
left join user on team.user_id=user.id
WHERE user.id IS NOT NULL;

方案 2:IFNULL 兜底,给空值填充默认值(谨慎使用)

业务上允许 “未知姓名” 这种脏数据时,用 IFNULL 对字段兜底,避免 NULL 入库。

⚠️ 不推荐优先使用,容易掩盖数据异常,适合数据迁移临时兼容场景。

insert into team_member(team_id,team_invite_id,name,user_id,user_phone,type,work_type,gender,role,state,status,campus_id,college_id) 
select team.id,0,IFNULL(user.name,'未知姓名'),user.id,user.phone,1,1,IFNULL(user.gender,''),'创始人',0,1,user.campus,team.college_id 
from team left join user on team.user_id=user.id;

方案 3:先排查脏数据(定位问题数据)

正式执行插入之前,先跑下面这条 SQL,查看哪些团队记录匹配不到用户,提前清理脏数据:

SELECT team.* 
FROM team 
LEFT JOIN user on team.user_id=user.id
WHERE user.name IS NULL;

踩坑总结

  1. LEFT JOIN 会产生 NULL 行,搭配 INSERT ... SELECT 批量插入时,一定要注意目标表的 NOT NULL 字段;
  2. ON 是连接阶段过滤,WHERE 是连接完成后过滤;LEFT JOIN 后加 IS NOT NULL 等价于内连接;
  3. 多表联查字段务必带上表别名(team.college_id),避免字段歧义 BUG;
  4. 优先从数据源过滤无效数据,不要依赖 IFNULL 兜底掩盖数据问题;
  5. 遇到 Column xxx cannot be null,排查顺序:先看字段是否 NOT NULL → 看联查会不会产出 NULL → 过滤脏数据或者兜底。

拓展小知识

同类型报错经常出现在 RIGHT JOIN、LEFT JOIN、子查询批量导入场景,原理一致:关联不上的一侧字段为 NULL,写入非空字段直接报错。

正文完
可以使用微信扫码关注公众号(ID:xzluomor)
post-qrcode
 0
评论(没有评论)
验证码