You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

向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
  • 修改注册表后需要重启SQL Server服务才会生效。

方法2:提前将Excel列设置为文本格式

在导入前,手动把包含长数字的列设置为文本格式,从源头避免驱动的类型推断:

  1. 打开Excel文件,选中目标列
  2. 右键选择「设置单元格格式」,切换到「数字」标签,选择「文本」
  3. 注意:如果已经输入了数字,需要双击每个单元格让格式生效(或者用「数据」选项卡的「分列」功能,最后一步选择文本格式)

这样驱动读取的时候就会直接把数字当作文本导入,不会转成指数格式。

方法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,步骤稍微复杂一点,但能更精准控制数据类型:

  1. 把Excel文件另存为XML格式
  2. 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

火山引擎 最新活动