Bulk Copy Commit Rows Without Errors

时间:2015-06-25 19:13:53

标签: c# sql sql-server

I have a process that takes a lists and inserts it into a database using SQL bulk copy because of how particularly large this list can be. It works fine, checks constraints and all which is perfect. The problem is, if I have 10,000 records and one of those records has an error, I still want to commit the other 9,999. Is there a way to do this other than manually checking each constraint before SQL bulk copy or inserting one at a time? Seems tedious and slow which kind of defeats the point. Thanks. var copy = new SqlBulkCopy(ConfigurationManager.ConnectionStrings["constr"].ConnectionString, SqlBulkCopyOptions.CheckConstraints) { DestinationTableName = obj.TableName }; var table = new DataTable(); copy.WriteToServer(table);

1 个答案:

答案 0 :(得分:2)

如果没有将batch size设置为1(这会破坏批量复制的目的)或者在复制之前预先检查数据,那么围绕此问题的正常方法是将其复制到具有相同内容的临时表中schema作为目标表但没有约束,删除会违反插入约束的行,然后从临时表中执行普通插入到您的实时表中。

const string _createTableString = "Create table #temp (/* SNIP */)";
const string _insertTableString = @"
declare @sql nvarchar(2000)
set @sql = N'INSERT INTO ' + QUOTENAME(@tableName) + N' SELECT * from #temp'
exec sp_executesql @sql";

using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["constr"].ConnectionString))
{
    connection.Open();
    using (var command = new SqlCommand(_createTableString, connection))
    {
        command.ExecuteNonQuery();
    }
    using (var copy = new SqlBulkCopy(connection))
    {
        copy.DestinationTableName = "#temp";
        copy.WriteToServer(table);
    }
    using (var command = new SqlCommand(_insertTableString, connection))
    {
        command.Parameters.AddWithValue("@tableName", obj.TableName)
        command.ExecuteNonQuery();
    }
}

请注意使用QUOTENAME确保没有SQL注入可以通过传递给obj.TableName的表名偷偷进入。