【问题标题】:Bulk insert from CSV file - skip duplicates从 CSV 文件批量插入 - 跳过重复项
【发布时间】:2014-12-15 13:15:49
【问题描述】:

更新:最终使用了 Johnny Bubriski 创建的这种方法,然后对其进行了一些修改以跳过重复项。像魅力一样工作,并且显然非常快。 链接:http://johnnycode.com/2013/08/19/using-c-sharp-sqlbulkcopy-to-import-csv-data-sql-server/

我一直在寻找这个问题的答案,但似乎找不到。我正在执行 T-SQL 批量插入以将数据从 csv 文件加载到本地数据库中的表中。我的陈述是这样的:

BULK INSERT Orders
FROM 'csvfile.csv'
WITH(FIELDTERMINATOR = ';', ROWTERMINATOR = '0x0a', FORMATFILE = 'formatfile.fmt', ERRORFILE = 'C:\\ProgramData\\Tools_TextileMagazine\\AdditionalFiles\\BulkInsertErrors.txt')
GO

SELECT * 
FROM Orders
GO

当我尝试插入重复的行(例如两次获取相同的 csv 文件)时出现异常,这会导致整个插入停止并回滚。可以理解,因为我违反了主键约束。现在我只是显示一个消息框,让用户知道 csv 文件中存在重复项,但这当然不是正确的解决方案,实际上根本不是解决方案。我的问题是,有什么方法可以忽略这些重复的行并跳过它们,只添加不重复的行?也许以某种方式尝试捕获?

如果不可能,从 csv 文件导入数据的“正确”(因为没有更好的词)方法是什么?这个例外给我带来了一些麻烦。我确实在某处读过,您可以设置一个临时表,将数据加载到其中并在插入之前在两个表之间选择不同的。但是使用批量插入真的没有更简单的方法吗?

【问题讨论】:

  • 将数据导入临时表,清理它们,然后将它们插入到目的地。否则,使用 SSIS 作为导入流程的一部分进行清理
  • St0ffer - 您能否详细说明您如何修改解决方案以跳过重复项?
  • @Ryan 很抱歉让您失望了,但大约 6 年后我什么都不记得了;)

标签: sql sql-server csv bulkinsert sql-server-2014


【解决方案1】:

首先,没有像 BULK INSERT WHERE NOT EXISTS 这样的直接解决方案。您可以使用以下解决方案。

使用 BULK INSERT 时有两种情况

  1. 您正在一个空表中批量插入
  2. 您正在大容量插入已填满的表中

案例 1 的解决方案: 设置 MAXERRORS = 0 设置 BATCHSIZE = csv 文件中的总行数

将上述语句与 BULK INSERT 一起使用会导致整个 BULK INSERT 操作回滚,即使存在单个错误,这也会阻止导入行,即使在少数行中存在错误。您需要解决所有导入错误才能完成导入操作。此方法可以防止导入 50 行,导入 30 行而其余不导入的情况。然后您必须在 CSV 文件中搜索失败的文件并重新导入它们或从 SQL 表中删除所有导入的行并再次执行 BULK INSERT。

案例 2 的解决方案: 1> 您可以在现有表上运行选择查询,右键单击并导出为 CSV。如果您有任何电子表格程序,然后将数据粘贴到导入数据下方,并在主键列上使用条件格式突出显示重复的行并将其删除。然后使用 BULK INSERT 操作。

2> 设置 MAXERRORS = 行数,并使用 BULK INSERT 导入 csv 文件。这是不安全且不推荐的方式,因为除了重复键错误之外可能还有其他类型的错误

3> 设置 BATCHSIZE = 1 和 MAXERRORS = 高数,并使用 BULK INSERT 导入 csv 文件。这将导入所有没有错误的行,并且将跳过任何有错误的行。如果数据集很小,并且您可以通过观察表列(例如显示缺失数字的 id 编号列)直观地识别未导入的行,这很有用。

4> 右键单击​​现有表,选择表为 > Crete to > 新查询窗口。只需重命名表名并更改为像 table_staging 这样的暂存名称。 BULK 在暂存表中插入,然后运行第二个查询以将数据从暂存表复制到主表,并使用 WHERE 子句检查行/pk是否存在。这是一种更安全的方法,但会强制您创建临时表。

【讨论】:

    【解决方案2】:

    您可以将MAXERRORS 属性设置为相当高的值,这将允许插入有效记录并忽略重复记录。不幸的是,这意味着数据集中的任何其他错误都不会导致加载失败。

    或者,您可以设置BATCHSIZE 属性,该属性将在多个事务中加载数据,因此如果有重复,它只会回滚批处理。

    一种更安全但效率较低的方法是将 CSV 文件加载到单独的空表中,然后如您所述将它们合并到您的订单表中。就个人而言,这是我的做法。

    这些解决方案都不是理想的,但我想不出在批量插入语法中忽略重复项的方法。

    【讨论】:

    • 是的,我不太喜欢您的前两个建议可能导致的不一致的想法。我想我会尝试使用虚拟桌子。
    • 我会把你的作为答案,因为它在技术上是正确的,即使我最终放弃了使用批量插入。
    • @St0ffer 你用什么代替了?
    • @MohammadAli 查看我的问题顶部的更新 :)
    猜你喜欢
    • 1970-01-01
    • 2020-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-27
    • 2012-03-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多