批量上传遇仅含表头的空文件:SQL Bulk Insert代码适配问询
这个问题我实战中遇到过好几次,当文件只有表头没数据时,直接跑原来的bulk insert肯定会报错——毕竟表头是文本字符串,和你表中Expiry(datetime类型)、Strike_Price(numeric类型)的字段类型不匹配。下面给你几个实用的解决思路,按需选就行:
方法1:先判断文件行数,仅当有数据时执行批量插入
这种思路是先确认文件里除了表头还有没有数据行,有再执行插入。需要用到xp_cmdshell来统计行数,注意它默认是禁用的,得先开权限:
-- 开启xp_cmdshell(仅需执行一次,后续无需重复运行) sp_configure 'show advanced options', 1; RECONFIGURE; sp_configure 'xp_cmdshell', 1; RECONFIGURE; GO
然后编写判断逻辑:
DECLARE @filePath NVARCHAR(255) = 'D:\Filewithdata.txt'; DECLARE @totalRows INT; DECLARE @cmd NVARCHAR(4000); -- 用findstr统计文件总行数(包括表头) SET @cmd = 'findstr /R /N "^" "' + @filePath + '" | find /C ":"'; EXEC xp_cmdshell @cmd, @output_variable = @totalRows; -- 如果总行数大于1(说明有数据行),执行批量插入(跳过表头) IF @totalRows > 1 BEGIN BULK INSERT TEST FROM @filePath WITH ( FIRSTROW = 2, -- 跳过第1行的表头,从第2行开始插入数据 FIELDTERMINATOR = ',', ROWTERMINATOR = '\n' ); PRINT '数据插入完成'; END ELSE BEGIN PRINT '文件仅含表头,无数据可插入'; END GO
小提示:findstr的统计方式能准确识别空行,比其他命令更可靠。
方法2:导入临时表过滤表头后插入(无需开启xp_cmdshell)
如果不想动服务器的xp_cmdshell权限,这个方法更安全:先把所有行(包括表头)导入到一个全varchar类型的临时表,再过滤掉表头行,转换类型后插入正式表:
-- 创建临时表,所有字段设为varchar,兼容表头和数据 CREATE TABLE #TempImport ( Client_Code Varchar(255), Segment Varchar(255), Symbol Varchar(255), Instrument Varchar(255), Expiry Varchar(255), Strike_Price Varchar(255), Opt_Type Varchar(255), Buy_Qty Varchar(255), Buy_Value Varchar(255), Sell_Qty Varchar(255), Sell_Value Varchar(255), Product Varchar(255) ); -- 导入文件所有内容(包括表头) BULK INSERT #TempImport FROM 'D:\Filewithdata.txt' WITH ( FIRSTROW = 1, FIELDTERMINATOR = ',', ROWTERMINATOR = '\n' ); -- 过滤表头行,转换数据类型后插入正式表 INSERT INTO TEST ( Client_Code, Segment, Symbol, Instrument, Expiry, Strike_Price, Opt_Type, Buy_Qty, Buy_Value, Sell_Qty, Sell_Value, Product ) SELECT Client_Code, Segment, Symbol, Instrument, TRY_CONVERT(DATETIME, Expiry), -- 尝试转换日期,失败返回NULL TRY_CONVERT(NUMERIC(18,8), Strike_Price), -- 尝试转换数值,失败返回NULL Opt_Type, Buy_Qty, Buy_Value, Sell_Qty, Sell_Value, Product FROM #TempImport -- 排除表头行:这里假设表头的Client_Code列值就是'Client_Code',可根据实际调整 WHERE Client_Code != 'Client_Code'; -- 清理临时表 DROP TABLE #TempImport; GO
如果文件只有表头,INSERT语句不会插入任何数据,也不会报错,很稳妥。
方法3:用TRY...CATCH捕获无数据的错误
这个方法最简洁,但要注意会过滤特定错误,适合你确定只有“无数据”这一种异常场景:
BEGIN TRY BULK INSERT TEST FROM 'D:\Filewithdata.txt' WITH ( FIRSTROW = 2, -- 跳过表头 FIELDTERMINATOR = ',', ROWTERMINATOR = '\n' ); PRINT '数据插入成功'; END TRY BEGIN CATCH -- 判断是否是无数据或类型转换失败的错误 IF ERROR_NUMBER() IN (4863, 4864) BEGIN PRINT '文件仅含表头,无数据可插入'; END ELSE BEGIN -- 其他错误正常抛出,方便排查 THROW; END END CATCH GO
错误码说明:4864对应“找不到数据行”的错误,4863对应“数据类型转换失败”的错误,刚好覆盖你遇到的场景。
内容的提问来源于stack exchange,提问作者Mittal
相关产品推荐
相关产品推荐

