SQLBulkCopy“插入或更新(如果存在)”的任何方法?

发布于 2024-10-16 01:12:31 字数 154 浏览 4 评论 0原文

我需要定期更新一个非常大的表,而 SQLBulkCopy 非常适合这一点,只是我有一个 2 列索引来防止重复。有没有办法使用 SQLBulkCopy 作为“插入或更新(如果存在)”?

如果没有,最有效的方法是什么?再次,我谈论的是一个包含数百万条记录的表。

谢谢

I need to update a very large table periodically and SQLBulkCopy is perfect for that, only that I have a 2-columns index that prevents duplicates. Is there a way to use SQLBulkCopy as "insert or update if exists"?

If not, what is the most efficient way of doing so? Again, I am talking about a table with millions of records.

Thank you

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

盗心人 2024-10-23 01:12:31

我发布了一个nuget包(SqlBulkTools)来解决这个问题。

下面是一个可以实现批量更新插入的代码示例。

var bulk = new BulkOperations();
var books = GetBooks();

using (TransactionScope trans = new TransactionScope())
{
    using (SqlConnection conn = new SqlConnection(ConfigurationManager
    .ConnectionStrings["SqlBulkToolsTest"].ConnectionString))
    {
        bulk.Setup<Book>()
            .ForCollection(books)
            .WithTable("Books")
            .AddAllColumns()
            .BulkInsertOrUpdate()
            .MatchTargetOn(x => x.ISBN)
            .Commit(conn);
    }

    trans.Complete();
}

对于非常大的表,可以选择添加表锁并暂时禁用非聚集索引。有关更多示例,请参阅 SqlBulkTools 文档

I published a nuget package (SqlBulkTools) to solve this problem.

Here's a code example that would achieve a bulk upsert.

var bulk = new BulkOperations();
var books = GetBooks();

using (TransactionScope trans = new TransactionScope())
{
    using (SqlConnection conn = new SqlConnection(ConfigurationManager
    .ConnectionStrings["SqlBulkToolsTest"].ConnectionString))
    {
        bulk.Setup<Book>()
            .ForCollection(books)
            .WithTable("Books")
            .AddAllColumns()
            .BulkInsertOrUpdate()
            .MatchTargetOn(x => x.ISBN)
            .Commit(conn);
    }

    trans.Complete();
}

For very large tables, there are options to add table locks and temporarily disable non-clustered indexes. See SqlBulkTools Documentation for more examples.

神回复 2024-10-23 01:12:31

我会将数据批量加载到临时暂存表中,然后将更新插入到最终表中。请参阅此处 进行更新插入的示例。

I would bulk load data into a temporary staging table, then do an upsert into the final table. See here for an example of doing an upsert.

所有深爱都是秘密 2024-10-23 01:12:31

不是一步完成,而是在 SQL Server 2008 中,您可以:

  • 批量加载到临时表中
  • 应用 MERGE 语句来更新/插入到您的真实表中

阅读有关 < a href="http://technet.microsoft.com/en-us/library/bb510625.aspx" rel="noreferrer">MERGE 语句

Not in one step, but in SQL Server 2008, you could:

  • bulk load into staging table
  • apply a MERGE statement to update/insert into your real table

Read more about the MERGE statement

感情旳空白 2024-10-23 01:12:31

而不是创建一个新的临时表,顺便说一句,这会消耗更多的空间和内存。

我使用 INSTEAD OF INSERT 创建了一个触发器,并在 MERGE 语句中使用。

但不要忘记在 SqlBulkCopy 中添加参数 SqlBulkCopyOptions.FireTriggers。

这是我的两分钱。

Instead of create a new temporary table, which BTW consume more space and memory.

I created a Trigger with INSTEAD OF INSERT and use inside MERGE statement.

But don't forget add the parameter SqlBulkCopyOptions.FireTriggers in the SqlBulkCopy.

This is my two cents.

指尖上的星空 2024-10-23 01:12:31

从@Ivan 得到了提示。对于那些可能需要的人,这就是我所做的。

create trigger yourschma.Tr_your_triger_name
    on yourschma.yourtable
    instead of INSERT
    as
    merge into yourschma.yourtable as target
    using inserted as source
    on (target.yourtableID = source.yourtableID)
    when matched then
        update
        set target.ID     = source.ID,
            target.some_column = source.some_column,
            target.Amount                       = source.Amount
    when not matched by target then
        insert (some_column, Amount)
        values (source.some_column, source.Amount);
go

Got a hint from @Ivan. For those who might need, here's what I did.

create trigger yourschma.Tr_your_triger_name
    on yourschma.yourtable
    instead of INSERT
    as
    merge into yourschma.yourtable as target
    using inserted as source
    on (target.yourtableID = source.yourtableID)
    when matched then
        update
        set target.ID     = source.ID,
            target.some_column = source.some_column,
            target.Amount                       = source.Amount
    when not matched by target then
        insert (some_column, Amount)
        values (source.some_column, source.Amount);
go
北音执念 2024-10-23 01:12:31

另一种选择是不使用临时表,而是使用带有表值参数的存储过程。将数据表传递给 sp 并在那里进行合并。

Another alternative would be to not use a temporary table but use a stored procedure with a table valued parameter. Pass a datatable to the sp and do the merge there.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文