MySQL导入CSV时无效日期报错,触发器无法捕获问题求助
解决LOAD DATA导入无效日期时触发器无法捕获错误的问题
问题核心
你遇到的问题本质是MySQL的字段类型校验优先级高于触发器执行:当脏表的fecha_fallo_notificacion字段是DATE类型时,LOAD DATA导入过程中,MySQL会先校验日期格式的合法性,遇到2023-09-31这类无效日期时,直接抛出1292错误并终止插入操作,此时BEFORE/AFTER INSERT触发器根本没有执行的机会,自然无法将错误信息写入errores_carga表。
另外你提供的触发器代码存在两个问题:
- 触发器名称与关联表名重复(
dirty_si_base_AFTER_INSERT既是触发器名又是表名),属于语法错误; - 用
STR_TO_DATE(...) IS NOT NULL判断日期有效性的逻辑不成立——遇到无效日期时,STR_TO_DATE会直接抛出1292错误,而非返回NULL,导致判断代码无法执行。
解决方案
步骤1:修改脏表的日期字段类型
将DATE类型改为VARCHAR(10),绕过MySQL的前置日期校验,让所有CSV数据都能先插入到脏表中,给触发器留足处理空间:
ALTER TABLE dirty_si_base MODIFY COLUMN fecha_fallo_notificacion VARCHAR(10);
步骤2:重新编写触发器(带错误捕获)
使用DECLARE CONTINUE HANDLER捕获STR_TO_DATE转换时的1292错误,标记无效日期并写入错误表。这里提供两种方案,可根据需求选择:
方案A:BEFORE INSERT触发器(提前处理脏数据)
在插入前校验,可将无效日期字段设为NULL,避免脏数据留存:
CREATE DEFINER=`root`@`localhost` TRIGGER `dirty_si_base_BEFORE_INSERT` BEFORE INSERT ON `dirty_si_base` FOR EACH ROW BEGIN DECLARE fecha_valida BOOLEAN; DECLARE temp_date DATE; -- 捕获日期转换错误(错误码1292),标记日期无效 DECLARE CONTINUE HANDLER FOR 1292 SET fecha_valida = FALSE; -- 初始化标记为有效 SET fecha_valida = TRUE; -- 尝试转换日期,若无效会触发上面的HANDLER SET temp_date = STR_TO_DATE(NEW.fecha_fallo_notificacion, '%Y-%m-%d'); -- 日期无效时写入错误表,并将字段设为NULL(可根据需求调整) IF NOT fecha_valida THEN INSERT INTO errores_carga(con, mensaje, campo, archivo, created_at) VALUES (CAST(NEW.id AS CHAR), 'La fecha no existe', 5, 'SI', NOW()); SET NEW.fecha_fallo_notificacion = NULL; END IF; END;
方案B:AFTER INSERT触发器(保留原始数据)
插入后再校验,保留CSV中的原始无效日期字符串:
CREATE DEFINER=`root`@`localhost` TRIGGER `dirty_si_base_AFTER_INSERT` AFTER INSERT ON `dirty_si_base` FOR EACH ROW BEGIN DECLARE fecha_valida BOOLEAN; DECLARE temp_date DATE; DECLARE CONTINUE HANDLER FOR 1292 SET fecha_valida = FALSE; SET fecha_valida = TRUE; SET temp_date = STR_TO_DATE(NEW.fecha_fallo_notificacion, '%Y-%m-%d'); IF NOT fecha_valida THEN INSERT INTO errores_carga(con, mensaje, campo, archivo, created_at) VALUES (CAST(NEW.id AS CHAR), 'La fecha no existe', 5, 'SI', NOW()); END IF; END;
步骤3:批量修正到目标表
当脏表数据处理完成后,可通过以下SQL将有效日期同步到目标表:
INSERT INTO 目标表(fecha_fallo_notificacion, 其他字段) SELECT STR_TO_DATE(fecha_fallo_notificacion, '%Y-%m-%d'), 其他字段 FROM dirty_si_base WHERE fecha_fallo_notificacion IS NOT NULL;
内容的提问来源于stack exchange,提问作者Julio Guerrero
相关产品推荐
相关产品推荐

