批量插入 - 捕获所有约束错误

时间:2016-08-03 10:01:42

标签: sql-server validation tsql bulkinsert

我正在尝试使用BULK INSERT收集文件中包含的所有格式和约束错误。我希望文件中的确切行代表每个错误和错误描述。

目前,我使用ERRORFILE选项收集文件中包含的所有格式错误。这给了我我需要的东西,但仅用于格式化错误。

我想对约束错误做同样的事情。如果我使用CHECK_CONSTRAINTS选项,我可以捕获错误,但批量插入终止。在检测到约束违规后,批量插入是否有任何方法可以继续插入行,以便我可以收集所有约束错误?

我可以对插入行的临时表进行约束检查(批量插入完成后),但我不想遵循这种方法,因为:

  1. 我无法获得约束条件中的确切行 发现违规行为
  2. 由于文件的性能原因 可能包含数百万行
  3. 更新

    输入文件是制表符分隔的文本文件,包含3列:ID,名称,描述

    以下是我用来读取/验证文件的代码:

    create table #MyTable (ID int not null, Name varchar(20) not null, Description varchar(60) not null)
    
    alter table #MyTable add check (ID != 1)
    
    begin try
      execute sp_executesql 'bulk insert #MyTable from ''' + @FilePath + ''' with (maxerrors = 1000,check_constraints,errorfile='''+@ErrorFilePath+''')'
    end try
    begin catch
    -- Here I am logging the constraint validation error
    end catch
    

    所需的输出是一个表,其中包含文件中的所有格式和约束错误。目前我在指定的errorfile中收到所有格式错误,并且我批量插入errorfile以获取具有结构的表中的错误

    RowNumber int, ErrorDescription nvarchar(max) not null
    

    除格式错误外,我还希望此表包含所有约束错误。目前,查询在第一个约束错误发生时终止(由于CHECK_CONSTRAINTS行为)。

1 个答案:

答案 0 :(得分:0)

最近我不得不导入数十万个XML文件,每个文件只包含一行。我的方法是在第一步中将所有文件放入数据库,然后检查文本长度,约束,值范围,转换问题......当遵循此方法时,您需要将所有列的数据类型声明为nvarchar(max)允许所有数据保存在临时表中。你永远不会知道你会得到什么。此表包含执行检查所需的所有信息,识别错误记录,使用单个SQL语句将转换后的数据转换并写入目标表。

CREATE TABLE #MyTable1 ([ID] varchar(max), [NAME] varchar(max), [DESCRIPTION] varchar(max));
CREATE TABLE #MyTable2 ([ID] int not null, [NAME] varchar(20) not null, [DESCRIPTION] varchar(60) not null);

EXEC sp_executesql 'bulk insert #MyTable from ''' + @FilePath + ''''
--> I'm not so familiar wit the right syntax. I hope it is right. The point is, don't do any checks here.

SELECT 
    TRY_CONVERT([ID])
   ,[NAME]
   ,[DESCRIPTION]
   --,CASE WHEN TRY_CONVERT([ID]) IS NULL AND [ID] IS NOT NULL        THEN 1 ELSE 0 END AS [CONVERSION_ERROR_ID]
   --,CASE WHEN [NAME] IS NOT NULL AND LEN([NAME]) > 20               THEN 1 ELSE 0 END AS [CONVERSION_NAME]
   --,CASE WHEN [DESCRIPTION] IS NOT NULL AND LEN([DESCRIPTION]) > 60 THEN 1 ELSE 0 END AS [CONVERSION_DESCRIPTION]
FROM 
   #MyTable1
WHERE
      CASE WHEN TRY_CONVERT([ID]) IS NULL AND [ID] IS NOT NULL        THEN 1 ELSE 0 END = 1 --
   OR CASE WHEN [NAME] IS NOT NULL AND LEN([NAME]) > 20               THEN 1 ELSE 0 END = 1 -- --> show only erroneous rows
   OR CASE WHEN [DESCRIPTION] IS NOT NULL AND LEN([DESCRIPTION]) > 60 THEN 1 ELSE 0 END = 1 --
   -- Insert additional checks concerning the not null settings  


INSERT #MyTable2 ([ID], [NAME], [DESCRIPTION])
SELECT 
    [ID]
   ,[NAME]
   ,[DESCRIPTION]
FROM 
   #MyTable1
WHERE
       CASE WHEN TRY_CONVERT([ID]) IS NULL AND [ID] IS NOT NULL        THEN 1 ELSE 0 END = 0 --
   AND CASE WHEN [NAME] IS NOT NULL AND LEN([NAME]) > 20               THEN 1 ELSE 0 END = 0 -- --> Write only those rows to #MyTable2 where no issues can be found
   AND CASE WHEN [DESCRIPTION] IS NOT NULL AND LEN([DESCRIPTION]) > 60 THEN 1 ELSE 0 END = 0 --
   -- Insert additional checks concerning the not null settings  

-- Please note, that I have not tested these statements