【问题标题】:SQL Bulk Insert with FIRSTROW parameter skips the following line带有 FIRSTROW 参数的 SQL 批量插入跳过以下行
【发布时间】:2009-06-22 21:03:56
【问题描述】:

我似乎无法弄清楚这是怎么回事。

这是我尝试批量插入 SQL Server 2005 的文件示例:

***A NICE HEADER HERE***
0000001234|SSNV|00013893-03JUN09
0000005678|ABCD|00013893-03JUN09
0000009112|0000|00013893-03JUN09
0000009112|0000|00013893-03JUN09

这是我的批量插入语句:

BULK INSERT sometable
FROM 'E:\filefromabove.txt
WITH
(
FIRSTROW = 2,
FIELDTERMINATOR= '|',
ROWTERMINATOR = '\n'
)

但是,由于某种原因,我能得到的唯一输出是:

0000005678|ABCD|00013893-03JUN09
0000009112|0000|00013893-03JUN09
0000009112|0000|00013893-03JUN09

第一条记录总是被跳过,除非我完全删除了标题并且不使用 FIRSTROW 参数。这怎么可能?

提前致谢!

【问题讨论】:

    标签: sql sql-server-2005 bulkinsert


    【解决方案1】:

    我认为您不能使用 BULK INSERT/BCP 跳过其他格式的行。

    当我运行这个时:

    TRUNCATE TABLE so1029384
    
    BULK INSERT so1029384
    FROM 'C:\Data\test\so1029384.txt'
    WITH
    (
    --FIRSTROW = 2,
    FIELDTERMINATOR= '|',
    ROWTERMINATOR = '\n'
    )
    
    SELECT * FROM so1029384
    

    我明白了:

    col1                                               col2                                               col3
    -------------------------------------------------- -------------------------------------------------- --------------------------------------------------
    ***A NICE HEADER HERE***
    0000001234               SSNV                                               00013893-03JUN09
    0000005678                                         ABCD                                               00013893-03JUN09
    0000009112                                         0000                                               00013893-03JUN09
    0000009112                                         0000                                               00013893-03JUN09
    

    看起来它需要'|'即使在标题数据中,因为它会读入第一列 - 将换行符吞入第一列。显然,如果您包含一个字段终止符参数,它希望每一行必须有一个。

    您可以通过预处理步骤去除该行。另一种可能性是只选择完整的行,然后处理它们(不包括标题)。或者使用可以处理此问题的工具,例如 SSIS。

    【讨论】:

    • 你是对的!当我添加 '||'到标题的末尾,它工作正常。我认为我将尝试从我插入的每个文件中删除标题。谢谢!
    • 这也适用于我使用逗号。同上,在插入之前要去掉标题。谢谢。
    【解决方案2】:

    也许检查标题是否与实际数据行具有相同的行尾(在ROWTERMINATOR 中指定)?

    更新:来自MSDN

    FIRSTROW 属性不是预期的 跳过列标题。跳过 BULK 不支持标头 插入语句。跳过行时, SQL Server 数据库引擎看起来 仅在场终止符处,并且 不验证中的数据 跳过行的字段。

    【讨论】:

    • 嗨,马克,是的,不幸的是,每一行都有一个 CRLF。不过,感谢您的意见。
    • 对于 CRLF 你需要使用ROWTERMINATOR = '\r\n'
    【解决方案3】:

    我发现将整行读入一列然后使用 XML 解析数据是最简单的。

    IF (OBJECT_ID('tempdb..#data') IS NOT NULL) DROP TABLE #data
    CREATE TABLE #data (data VARCHAR(MAX))
    
    BULK INSERT #data FROM 'E:\filefromabove.txt' WITH (FIRSTROW = 2, ROWTERMINATOR = '\n')
    
    IF (OBJECT_ID('tempdb..#dataXml') IS NOT NULL) DROP TABLE #dataXml
    CREATE TABLE #dataXml (ID INT NOT NULL IDENTITY(1,1) PRIMARY KEY CLUSTERED, data XML)
    
    INSERT #dataXml (data)
    SELECT CAST('<r><d>' + REPLACE(data, '|', '</d><d>') + '</d></r>' AS XML)
    FROM #data
    
    SELECT  d.data.value('(/r//d)[1]', 'varchar(max)') AS col1,
            d.data.value('(/r//d)[2]', 'varchar(max)') AS col2,
            d.data.value('(/r//d)[3]', 'varchar(max)') AS col3
    FROM #dataXml d
    

    【讨论】:

    • 这是一个很棒的脚本,可以避免使用 SSIS。它只允许我导入第一行,检查它是否与目标行一致,然后继续导入除标题之外的所有数据。谢谢!
    【解决方案4】:

    你可以使用下面的sn-p

    BULK INSERT TextData
    FROM 'E:\filefromabove.txt'
    WITH
    (
    FIRSTROW = 2,
    FIELDTERMINATOR = '|',  --CSV field delimiter
    ROWTERMINATOR = '\n',   --Use to shift the control to next row
    ERRORFILE = 'E:\ErrorRows.csv',
    TABLOCK
    )
    

    【讨论】:

      【解决方案5】:

      让 SQL 处理引号转义和其他所有操作

      BULK INSERT Test_CSV
      FROM  'C:\MyCSV.csv' 
      WITH (
       FORMAT='CSV'
       --FIRSTROW = 2,  --uncomment this if your CSV contains header, so start parsing at line 2
      );
      

      关于其他答案,这里也是有价值的信息:

      我一直在所有答案中看到这一点:ROWTERMINATOR = '\n'
      \n 表示 LF,它是 Linux 风格的 EOL

      在 Windows 中,EOL 由 2 个字符 CRLF 组成,因此您需要 ROWTERMINATOR = '\r\n'

      【讨论】:

        【解决方案6】:

        考虑到在从非 SQL 数据源将 BCP 导入 SQL Server 后,某些数据会受到怎样的破坏,我建议先将所有 BCP 导入到一些暂存表中。

        例如

        截断表 Address_Import_tbl

        批量插入 dbo.Address_Import_tbl FROM 'E:\external\SomeDataSource\Address.csv' 和 ( FIELDTERMINATOR = '|',ROWTERMINATOR = '\n',MAXERRORS = 10 )

        确保 Address_Import_tbl 中的所有列都是 nvarchar(),以使其尽可能不可知,并避免类型转换错误。

        然后对 Address_Import_tbl 应用您需要的任何修复。就像删除不需要的标题一样。

        然后运行 ​​INSERT SELECT 查询,从 Address_Import_tbl 复制到 Address_tbl,以及您需要的任何数据类型转换。例如,将导入的日期转换为 SQL DATETIME。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-04-24
          • 1970-01-01
          • 1970-01-01
          • 2013-03-16
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多