使用带WHERE IN子句的SELECT执行INSERT时出现数据截断错误
解决INSERT...SELECT触发Data Truncation错误的问题(明明已过滤软删除记录)
听起来你碰到了个有点迷惑的问题——单独执行SELECT能拿到预期的未软删除记录,但套进INSERT里就报数据截断错误,还怀疑是不是有软删除记录混进来?咱们一步步拆解排查:
1. 先排查字段类型/长度不匹配(最常见原因)
Data Truncation错误大概率是源表(structures)和目标表(buildings)的对应字段类型、长度不兼容导致的,比如:
structures.name是VARCHAR(100),但buildings.name仅定义为VARCHAR(50),当SELECT结果里有超过50字符的名称时,插入就会触发截断- 或者字段类型不一致,比如源字段是TEXT,目标是VARCHAR且长度受限,也会出问题
你可以用这两条语句对比两张表的字段定义:
DESCRIBE structures; DESCRIBE buildings;
重点关注name和description的类型、长度、是否允许NULL这些属性。
2. 验证SELECT的实际结果(别被表象误导)
虽然你说单独跑SELECT没问题,但有可能在测试SELECT和执行INSERT的间隙,数据发生了变更?或者会话环境不同导致结果有差异?
建议把SELECT结果临时存到临时表,再仔细检查:
CREATE TEMPORARY TABLE temp_selected AS SELECT structures.name, structures.description FROM structures WHERE structures.structure_id IN (1, 2, 3, 4) AND structures.deleted_at IS NULL; -- 查看数据行数、字段长度,确认是否有异常 SELECT COUNT(*) AS total_rows, MAX(LENGTH(name)) AS max_name_length, MAX(LENGTH(description)) AS max_desc_length FROM temp_selected; -- 顺便验证deleted_at是否真的全为NULL SELECT DISTINCT deleted_at FROM structures WHERE structure_id IN (1,2,3,4);
这样能确认你要插入的数据是否真的符合buildings表的限制,也能彻底排查有没有软删除记录混进来。
3. 检查触发器或隐式转换的干扰
- 如果buildings表存在BEFORE INSERT触发器,可能会在插入时修改字段值,间接触发截断错误
- MySQL的隐式类型转换也可能导致问题,比如把数字类型转成字符串时长度超出限制
你可以先查看buildings表的触发器:
SHOW TRIGGERS LIKE 'buildings';
如果有触发器,可以临时禁用后再试一次INSERT,验证是否是触发器导致的问题。
4. 开启严格模式获取更详细的错误信息
默认MySQL可能不会给出截断错误的具体细节,你可以开启严格SQL模式,拿到更精准的报错:
SET sql_mode = 'STRICT_TRANS_TABLES';
再执行你的INSERT语句,就能看到到底是哪个字段、哪条数据触发了截断。
内容的提问来源于stack exchange,提问作者Josh




