【问题标题】:Convert scientific notation to float when using OpenRowSet to import a .CSV file使用 OpenRowSet 导入 .CSV 文件时将科学计数法转换为浮点数
【发布时间】:2011-11-20 08:18:41
【问题描述】:

我正在使用 openrowset 将 csv 文件导入 SQL Server。 csv 文件中的一列包含科学计数法 (1.08E+05) 的数字以及它正在插入的表中的列

默认情况下,它会将值导入为 1 并忽略 .08E+05。

我尝试在执行查询时使用 cast() 和 convert() 直接转换值,并将表中的数据类型设置为字符串并将其导入。所有这些方法都具有相同的行为,即忽略 .08E+05。

有没有办法将值导入为 108000 而不是 1 而无需 .08E+05 而无需更改 csv 文件本身?

将数据类型设置为 varchar 并读取 csv 文件似乎与以下代码具有相同的效果:

CREATE TABLE #dataTemp (StartDate datetime, Value varchar(12))

SET @insertDataQuery = 'SELECT Date, CSVValue from OpenRowset(''MSDASQL'', ''Driver={Microsoft Text Driver (*.txt; *.csv)}; DefaultDir=' 
SET @insertDataQuery = @insertDataQuery + 'C:\Data\;'',''SELECT * FROM '+ '11091800.csv' + ''')'

INSERT INTO #dataTemp EXEC(@insertDataQuery)

SELECT * FROM #dataTemp

并非 CSV 文件中的所有值都有科学记数法,而没有它的值,例如81000 没有问题。

【问题讨论】:

    标签: sql-server scientific-notation openrowset


    【解决方案1】:

    对于BULK INSERT 方法,我经常发现首先将数据移动到所有 varchars 的表中,然后去掉像带引号的分隔符和修复格式这样的无关内容更简单。我记得有一段时间摆脱科学记数法,你可以玩 varchar 表,直到你做对了。我记得尝试过各种精度/比例组合,直到我最终找到一个兼容的组合。我想对我来说是FLOAT 然后是DECIMAL(24,12)...

    SELECT CONVERT(DECIMAL(24, 12), CONVERT(FLOAT, '1.08E+05'));

    编辑添加我所做的以尝试重现和/或展示一种不那么复杂的方式。

    我创建了一个非常简单的 CSV 文件:

    StartDate,Value
    20110808,81000
    20110808,1.08E+05
    

    然后我运行了以下代码(出于某种原因,我无法让 MSDASQL 在我的机器上运行以挽救我的生命):

    CREATE TABLE #dataTemp(StartDate DATETIME, Value VARCHAR(32));
    
    BULK INSERT #dataTemp FROM 'C:\data\whatever.csv' 
        WITH (ROWTERMINATOR='\n', FIELDTERMINATOR=',', FIRSTROW = 2);
    
    SELECT * FROM #dataTemp
    GO
    SELECT StartDate, CONVERT(INT, CONVERT(FLOAT, Value)) FROM #dataTemp;
    GO
    DROP TABLE #dataTemp;
    

    结果:

    StartDate               Value
    ----------------------- --------
    2011-08-08 00:00:00.000 81000
    2011-08-08 00:00:00.000 1.08E+05
    
    StartDate               (No column name)
    ----------------------- ----------------
    2011-08-08 00:00:00.000 81000
    2011-08-08 00:00:00.000 108000
    

    【讨论】:

    • 实际上在你的情况下,现在我正在重新阅读你可能只使用SELECT CONVERT(INT, CONVERT(FLOAT, '1.08E+05')); 的问题 - 我上次处理科学记数法时,我正在处理来自 LogMan 的性能计数器,我绝对需要小数位...
    • 如果我明确提供值,上述任何解决方案都有效。在 CSV 文件中,我有一个值的列名,如果我使用它,例如 CONVERT(INT, CONVERT(FLOAT, COLUMN_NAME_IN_CSV)) 我仍然会得到它只读取第一个数字的行为。想法?
    • 我的想法仍然是先批量插入 varchars 表。当您的 insert ... select from openrowset 查询尝试将表类型与查询中的元数据匹配时,可能会发生其他事情。如果您先插入 varchar,则不会在意...
    • 这是有道理的,但是将数据类型设置为 varchar 会给我同样的行为。我在上面的查询中添加了一个示例。
    • 请尝试我更新的答案中的方法。如果您仍然遇到转换错误,您将不得不尝试缩小导致问题的值 - 您可能在该列中的数据无法按照您预期的方式进行转换。
    【解决方案2】:

    会把它当成真正的作品吗?

    select cast('1.08E+05' as real)
    

    【讨论】:

      【解决方案3】:

      首先,您拥有科学记数法这一事实意味着它可能的 Excel 或其他创建该值的程序丢失了一些数据....换句话说,记数法中的原始数字已被转换,因此一些数字并且失去了准确性。这是许多从 Excel 和 CSV 转换的 Microsoft 产品的问题。

      其次,这里有一个更好的转换块,将数字转换为字符串:

      CONVERT(nvarchar(255),LTRIM(RTRIM(str(ISNULL(YOUR_NUMBER,0),20,0))))
      

      【讨论】:

      • .....丢失了一些数据......这正是许多从 Excel 和 CSV 转换的 Microsoft 产品的问题......加一。没有安装 Excel 几乎是任何类型数据工作的先决条件。问题是让您的客户卸载 Excel 非常困难 :)
      猜你喜欢
      • 1970-01-01
      • 2011-11-19
      • 1970-01-01
      • 2014-09-25
      • 2014-07-01
      • 2021-12-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多