向SQL Server上传Excel文件时长数字转指数格式的解决方法咨询
解决Excel导入SQL Server时长数字自动转为指数格式的问题
这个问题我之前帮不少开发者处理过,核心原因是Microsoft.ACE.OLEDB.12.0驱动会自动推断Excel列的数据类型,如果长数字列的前几行被识别为数值型,哪怕你数据库字段是varchar,驱动也会先把数字转成指数格式再导入。下面给你几个靠谱的解决办法,按优先级排序:
方法1:修改连接字符串,强制驱动按文本读取混合类型列
这是最直接的方案,在你的OPENROWSET连接字符串里加上IMEX=1参数,它会强制驱动把包含混合数据类型的列当作文本处理,避免数值型自动转指数。修改后的语句如下:
SELECT * INTO FEED_TEMP_TABLE FROM OPENROWSET( 'Microsoft.ACE.OLEDB.12.0', 'Excel 12.0;Database=C:\TestData\PRS_AGENT_VZ.xlsx;HDR=YES;IMEX=1', [Sheet1$] )
不过要注意两个细节:
- 默认情况下,驱动只会扫描前8行来推断数据类型(这个由注册表的
TypeGuessRows控制)。如果你的长数字列前8行都是普通短数字,驱动还是会识别为数值型。这时候需要修改注册表:- 32位系统:找到
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Jet\4.0\Engines\Excel,把TypeGuessRows改成0(表示扫描所有行) - 64位系统:找到
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Jet\4.0\Engines\Excel,同样修改TypeGuessRows为0
- 32位系统:找到
- 修改注册表后需要重启SQL Server服务才会生效。
方法2:提前将Excel列设置为文本格式
在导入前,手动把包含长数字的列设置为文本格式,从源头避免驱动的类型推断:
- 打开Excel文件,选中目标列
- 右键选择「设置单元格格式」,切换到「数字」标签,选择「文本」
- 注意:如果已经输入了数字,需要双击每个单元格让格式生效(或者用「数据」选项卡的「分列」功能,最后一步选择文本格式)
这样驱动读取的时候就会直接把数字当作文本导入,不会转成指数格式。
方法3:导入后用SQL函数转换指数格式字符串
如果已经导入了指数格式的数据,可以用SQL函数把它转成正常的数字字符串。比如用STR()函数(注意精度设置):
UPDATE FEED_TEMP_TABLE SET YourLongNumberColumn = STR(CAST(YourLongNumberColumn AS FLOAT), 15, 0)
或者用FORMAT()函数(SQL Server 2012及以上支持):
UPDATE FEED_TEMP_TABLE SET YourLongNumberColumn = FORMAT(CAST(YourLongNumberColumn AS FLOAT), 'N0')
不过这个方法是事后补救,不如前两种方法彻底,而且要注意浮点数的精度丢失问题,如果你的数字超过了FLOAT的精度范围,可能会有误差。
方法4:使用OPENXML替代OPENROWSET(备选)
如果上面的方法都不行,可以试试用OPENXML来导入Excel,步骤稍微复杂一点,但能更精准控制数据类型:
- 把Excel文件另存为XML格式
- 用
sp_xml_preparedocument加载XML,然后用OPENXML读取,指定列的类型为VARCHAR
示例代码大概是这样:
DECLARE @XmlDocumentHandle INT DECLARE @XmlDocument VARCHAR(MAX) -- 读取XML文件内容 SELECT @XmlDocument = BulkColumn FROM OPENROWSET(BULK 'C:\TestData\PRS_AGENT_VZ.xml', SINGLE_BLOB) AS x -- 准备文档 EXEC sp_xml_preparedocument @XmlDocumentHandle OUTPUT, @XmlDocument -- 导入数据,指定列类型 SELECT * INTO FEED_TEMP_TABLE FROM OPENXML(@XmlDocumentHandle, '/Workbook/Worksheet/Table/Row', 2) WITH ( Column1 VARCHAR(20), -- 把长数字列指定为VARCHAR Column2 INT, -- 其他列... ) -- 释放文档 EXEC sp_xml_removedocument @XmlDocumentHandle
这个方法虽然麻烦,但能完全避免驱动自动推断类型的问题,适合数据格式复杂的场景。
内容的提问来源于stack exchange,提问作者Hur Abbas




