【问题标题】:BULK INSERT inserts delimiter instead of default NULL value for empy fieldBULK INSERT 插入分隔符而不是空字段的默认 NULL 值
【发布时间】:2017-02-13 11:28:30
【问题描述】:

我正在尝试使用 BULK INSERT 插入一些行:

CREATE TABLE Foo (
  Id UNIQUEIDENTIFIER NOT NULL PRIMARY KEY DEFAULT newsequentialid(),
  Name NVARCHAR(255) NULL,
  CreatedOn DATETIME NOT NULL DEFAULT GETDATE(),
  CreatedBy NVARCHAR(255) NOT NULL DEFAULT SUSER_NAME(),
  ModifiedOn DATETIME NULL DEFAULT NULL,
  ModifiedBy NVARCHAR(255) NULL DEFAULT NULL
);

我从具有 UTF8 编码、分隔符的逗号和行尾的 LF 的 CSV 文件插入:

 ,Fizz,,,,,

我的 BULK INSERT 语句如下所示:

BULK INSERT Foo 
FROM 'C:\foo.csv' 
WITH (CODEPAGE = '65001', FIELDTERMINATOR = ',' , ROWTERMINATOR = '0x0a');

但插入行的最后一个字段(ModifiedBy)的值为','(逗号分隔符:

49625A3B-DCF1-E611-8D73-B00594F7CD91    Fizz    2017-02-13 12:04:48.223 sa  NULL    ,

我做错了什么以及如何让 BULK INSERT 将最终字段插入为 NULL(默认值)而不是 ','?

【问题讨论】:

  • 我看到那里有六个逗号,最后一个不是必需的。

标签: sql-server bulkinsert


【解决方案1】:

如果数据文件的第一行中没有列名,或者文件中每个位置的值,或者数据文件中所有行变体的完整示例,则必须假设:

  1. 行终止符还应包括字段终止符,或者
  2. 数据源中有一个未知的附加列未在表中说明。

它可能不太常见,但字段终止符也包含在行终止符中并不罕见。事实上,许多examples on MSDN for bulk insertfieldterminator 显示为rowterminator 的前导部分。

此解决方案假定rowterminatorfieldterminator 的一部分,类似于MSDN 上的示例:

bulk insert Foo 
from 'C:\foo.csv' 
with (
    codepage = '65001'
  , fieldterminator = ',' 
  , rowterminator = '0x2c0a'
  );

【讨论】:

  • 虽然您的解决方案呈现了所需的输出,但我知道这是错误的。问题的根本原因是输入有七个位置(六个逗号),并且您的解决方案假定这个额外的逗号是行终止符的一部分 - 对于每一行。
  • @MarcusViniciusPompeu 我认为假设我的解决方案是错误的可能是冒昧的。您假设输入有七个位置,但鉴于文件不包含每个位置的列标题或值,因此没有依据来断定它是有七个位置还是六个位置。我不能说哪个更有可能,但许多examples on MSDN for bulk insertfieldterminator 显示为rowterminator 的前导部分。
【解决方案2】:

在分配其他列之后,表的最后一列接收输入行中的所有剩余数据,显然没有进行解析。如果将 100 个逗号放在输入行中,则导入表的最后一列将有 95 个逗号(我通过快速测试验证了这一点)。正如 Marcus 还指出的那样,6 列布局必须有 5 个分隔符。

如果您无法从输入文件中删除额外的字段,您可以使用格式文件进行列映射,以排除最后一列,该列在https://msdn.microsoft.com/en-us/library/ms187908.aspx中进行了解释

如果您的输入文件确实用于 6 列,并且按照惯例,最后一个分隔符在那里,即“每列之后有一个分隔符”而不是“列之间的分隔符”,那么 @SqlZim 的解决方案应该可以正常工作大多。但话又说回来,您必须确保在一行中的最后一个分隔符之后(例如手动编辑时)没有添加空格等,否则该行的导入将失败,因为它与行分隔符字符不匹配。所以,为了更简单,我再次建议使用列映射方法,为最后一个分隔符添加一个虚拟字段定义,并在导入期间跳过它。

看起来 Sql server 打算变得灵活或选择不丢失孤立数据,但造成的混乱多于有用。

【讨论】:

  • 说够了:-)
【解决方案3】:

只数逗号...

Foo 表有 列,而给定的输入有 个位置。

假定最后一个逗号是ModifiedBy 列的值。

Id,NAME,CreatedOn,CreatedBy,ModifiedOn ,ModifiedBy,?

输入,Fizz,,,,,,,带有七个逗号,将呈现,,ModifiedBy

【讨论】:

    【解决方案4】:

    我想,你没有什么选择。

    i) 更改批量插入方法,改为使用 OPENROWSET 或 OPENQUERY。IT 允许您提及列名。示例链接,

    https://www.mssqltips.com/sqlservertip/1207/different-options-for-importing-data-into-sql-server/

    ii) 如果 i) 不被您接受,那么您可以在表上定义“插入后”触发器,您可以在其中再次将 modifiedDate 更新为 null。

    我认为解决方案一是完美的。

    【讨论】:

      猜你喜欢
      • 2016-08-30
      • 2014-09-16
      • 1970-01-01
      • 2020-10-12
      • 2011-03-29
      • 2012-12-29
      • 1970-01-01
      • 1970-01-01
      • 2012-07-18
      相关资源
      最近更新 更多