Laravel项目中如何将含datetime列的CSV正确导入MySQL(timestamp类型)
解决CSV导入MySQL日期格式及字段为空问题
核心问题排查
你的语句执行后出现字段为空、日期列未正确赋值,主要有两个原因:
- 日期格式串不匹配:CSV里的日期是
June, 26 2018 07:28:39(月份全称+逗号分隔),但你用的%b-%d-%Y是月份缩写+横杠分隔,完全不匹配,导致STR_TO_DATE返回NULL,触发列的默认值。 - 字段列表不完整:你提到实际列数更多,但
INTO TABLE后只指定了4个字段/变量,MySQL会按顺序匹配CSV列,多余的列会被丢弃,未被指定的表字段则会用默认值(空或0)填充。
分步修正方案
1. 修正日期转换的格式串
把STR_TO_DATE的格式串改成和CSV日期完全匹配的'%M, %d %Y %H:%M:%S':
%M:匹配月份全称(如June),:匹配日期前的逗号和空格%d %Y %H:%M:%S:匹配日、年、时分秒
2. 补全所有字段/变量的对应关系
必须保证INTO TABLE后的字段/变量顺序和CSV的列顺序完全一致,所有列都要列出来:
- 不需要转换的列,直接写表字段名
- 需要转换的日期列,用@临时变量接收,再通过
SET转换赋值
3. 完整的LOAD DATA语句(含表头处理)
假设你的CSV第一行是表头,且列顺序为region,start_year,added,published,col1,col2(请补充你实际的其他列),修正后的语句如下:
LOAD DATA INFILE 'C:/Users/rasha/Downloads/Data.csv' INTO TABLE data FIELDS TERMINATED BY ';' -- 确认CSV分隔符确实是分号,若之前varchar导入用的是逗号,改成',' LINES TERMINATED BY '\n' IGNORE 1 LINES -- 跳过CSV的表头行 (region, start_year, @added_temp, @published_temp, col1, col2) -- 补全所有列 SET added = STR_TO_DATE(@added_temp, '%M, %d %Y %H:%M:%S'), published = STR_TO_DATE(@published_temp, '%M, %d %Y %H:%M:%S');
4. Laravel环境下的执行注意事项
在Laravel中执行原生的LOAD DATA INFILE,需要注意两点:
- 开启本地文件导入权限:在
config/database.php的mysql配置中添加PDO::MYSQL_ATTR_LOCAL_INFILE选项:'mysql' => [ // ...其他配置项 'options' => extension_loaded('pdo_mysql') ? array_filter([ PDO::MYSQL_ATTR_LOCAL_INFILE => true, ]) : [], ], - 使用
DB::unprepared()执行语句(因为该语句不支持预处理):use Illuminate\Support\Facades\DB; DB::unprepared(" LOAD DATA INFILE 'C:/Users/rasha/Downloads/Data.csv' INTO TABLE data FIELDS TERMINATED BY ';' LINES TERMINATED BY '\n' IGNORE 1 LINES (region, start_year, @added_temp, @published_temp, col1, col2) SET added = STR_TO_DATE(@added_temp, '%M, %d %Y %H:%M:%S'), published = STR_TO_DATE(@published_temp, '%M, %d %Y %H:%M:%S'); ");
验证建议
先截取CSV的前10行做测试导入,检查:
- 所有非日期字段是否正确赋值
added和published列是否显示为正常的datetime格式,能执行日期对比操作
内容的提问来源于stack exchange,提问作者Rashad Khan
相关产品推荐
相关产品推荐

