【问题标题】:SqlBulkCopy Ignore Duplicate Records of Datatable From DataBaseSqlBulkCopy 忽略数据库中数据表的重复记录
【发布时间】:2015-07-10 12:22:00
【问题描述】:

我可以从我传递给 SqlBulkCopy 的数据表中忽略 sql 数据库中已经存在的数据的重复记录吗?如果是,那么如何,如果否和其他选项,请解释我。

【问题讨论】:

  • 记录中的主键呢?记录没有主键吗?
  • 一种可能的解决方案是使表的列唯一。为此,我们必须在表上创建一个索引,其中包含我们要检查唯一性的列名。

标签: c# asp.net .net


【解决方案1】:

不,这不是内置的。您需要先清理客户端上的数据或插入临时表。

【讨论】:

    【解决方案2】:

    正如之前的海报所说,这不是内置的。我使用以下方法实现了类似的功能:

    接受带有您需要的数据的 TableValuedParameter 的 SQL 存储过程。

    在存储过程中,然后我将所有记录插入到临时表中。一旦你有了它,你就可以在你的存储过程中使用 SQL 的 MERGE 语句在它不存在的地方插入数据。

    因此,让我们假设我们的数据只是存储在 people 表中的人名。我们只持有一个 ID 和一个名字。我还假设这张桌子被称为“人”。

    以下是我如何创建表值参数类型(在 SQL Server 中创建)

    CREATE TYPE udt_person AS TABLE(
    [id] [INT] NOT NULL,
    [name] [nvarchar(50)] NULL
    )
    GO
    

    我现在创建存储过程:

    CREATE PROCEDURE SaveNewPeople @pPeople udt_Person
    AS
    BEGIN
        -- Create Temp table
        CREATE TABLE #tmpPeople (id INT, name VARCHAR 50)
    
        -- We will stage all data passed in into temp table
        INSERT INTO #tmpPeople
        SELECT id, name FROM @pPeople
    
        -- NB: you will need to think about locking strategy a bit here
        MERGE people AS p
        USING #tmpPeople AS t
        ON p.id = t.id
        WHEN NOT MATCHED BY TARGET THEN
            -- We want to insert new person
            INSERT (id, name) VALUES (t.id, t.name)
        WHEN MATCHED THEN
            -- you may not need this, assume updating name for example
            UPDATE SET p.name = t.name
    
    END
    

    现在我们有了 SQL。

    让我们在 C# 中创建大量数据:

    DataTable ppl = new DataTable();
    ppl.Columns.Add("id", typeof(int));
    ppl.Columns.Add("name", typeof(string));
    
    // table is created, let's add some people
    var bob = ppl.NewRow();
    bob["id"] = 1;
    bob["name"] = "Bob";
    ppl.Rows.Add(bob);
    
    var jim = ppl.NewRow();
    jim["id"] = 2;
    jim["name"] = "Jim";
    ppl.Rows.Add(jim);
    
    // that's enough people for now, let's call the stored procedure
    using(var conn = new SqlConnection("YouConnStringHere"))
    {
        using(var cmd = new SqlCommand("SaveNewPeople", conn))
        {
            cmd.CommandType = CommandType.StoredProcedure;
    
            var tvp = new SqlParameter
            {
              ParameterName = "@pPeople",
              SqlDbType = SqlDbType.Structured,
              Value = ppl,
              TypeName = "udt_person"
            }
            cmd.Parameters.Add(tvp);
            conn.Open();
            cmd.ExecuteNonQuery();
        }
    
    }
    

    希望这能给你这个想法。如果您随后修改了 C# 数据表,您应该会看到插入、更新或忽略的行。

    祝你好运。

    【讨论】:

    • 是的,谢谢 GinjaNinja。我明白了你所说的。您能否也给我一个表值函数和 SQL 合并语句的代码示例。我正在使用 Sql Server 2000 和 .net 2.0
    • 我修改了上面的帖子,然后注意到您使用的是 SQL 2000。这不起作用,对不起!
    【解决方案3】:

    另一种方法是创建一个数据库触发器来替换由 SqlBulkCopy 发起的插入。性能会受到阻碍,具体取决于批次大小等因素,但它仍然有效。

    CREATE TABLE [dbo].[TempTable] (
        [Id] INT IDENTITY PRIMARY KEY,
        [Val] NVARCHAR(20)
    )
    
    GO
    
    CREATE OR ALTER TRIGGER [IgnoreDuplicates] ON [dbo].[TempTable] 
    INSTEAD OF INSERT 
    AS 
    BEGIN
        SET NOCOUNT ON
        INSERT INTO [dbo].[TempTable]([Val])
        SELECT [Val] FROM [INSERTED] WHERE [Val] NOT IN (
            SELECT [Val] FROM [dbo].[TempTable]
        )
    END
    
    GO
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-10-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多