在T-SQL中“合并”两个表 - 替换或保留重复的ID

时间:2009-04-28 03:08:43

标签: sql tsql merge

我有一个使用相当大的表(数百万行,大约30列)的Web应用程序。我们称之为TableA。在30列中,此表有一个名为“id”的主键,另一列名为“campaignID”。

作为应用程序的一部分,用户可以上传与新“广告系列”相关的新数据集。

这些数据集与TableA具有相同的结构,但通常只有大约10,000-20,000行。

新数据集中的每一行都会有一个唯一的“ID”,但它们都会共享相同的campaignID。换句话说,用户正在加载新“广告系列”的完整数据,因此所有10,000行都具有相同的“campaignID”。

通常,用户正在上传新广告系列的数据,因此TableA中没有具有相同campaignID的行。由于“id”对于每个广告系列都是唯一的,因此每个新数据行的ID在TableA中都是唯一的。

但是,在极少数情况下,用户尝试为已存在于数据库中的“广告系列”加载一组新行,则要求首先从TableA中删除该广告系列的所有旧行,然后插入来自新数据集的新行。

所以,我的存储过程很简单:

  1. BULK将新数据插入临时表(#tableB)
  2. 使用相同的campaignID
  3. 删除TableA中的所有现有行
  4. INSERT INTO表A([columns])SELECT [columns]来自#TableB
  5. 掉落#TableB
  6. 这很好用。

    但新要求是在用户上传新数据以处理“重复”时为用户提供3个选项 - 用户正在为已在TableA中的广告系列上传数据的实例。

    1. 使用相同的campaignID删除TableA中的所有数据,然后插入#TableB中的所有新数据。 (这是旧行为。使用此选项,它们永远不会重复。)
    2. 如果#TableB中的行与TableA中的行具有相同的ID,则使用#TableB中的行更新TableA中的该行(实际上,这是用新数据“替换”旧数据)
    3. 如果#TableB中的行与TableA中的行具有相同的ID,则忽略#TableB中的该行(实质上,这是保留原始数据,并忽略新数据)。
    4. 用户无法逐行选择此选项。她选择如何合并数据,并将此逻辑应用于整个数据集。

      在我使用MySQL的类似应用程序中,我使用“LOAD DATA INFILE”函数,使用“REPLACE”或“IGNORE”选项。但我不知道如何使用SQL Server / T-SQL执行此操作。

      任何解决方案都需要足够高效来处理TableA有数百万行的事实,而#TableB(新数据集)可能有10k-20k行。

      我搜索了类似“Merge”命令(SQL Server 2008似乎支持的东西),但我只能访问SQL Server 2005.

      在粗糙的伪代码中,我需要这样的东西:

      如果用户选择选项1: [我都在这里 - 我有这个工作]

      如果用户选择选项2(替换):

      merge into TableA as Target
      using #TableB as Source
          on TableA.id=#TableB.id
      when matched then 
          update row in TableA with row from #TableB
      when not matched then
          insert row from #TableB into TableA
      

      如果用户选择选项3(保留):

      merge into TableA as Target
      using #TableB as Source
          on TableA.id=#TableB.id
      when matched then 
          do nothing
      when not matched then
          insert row from #TableB into TableA
      

2 个答案:

答案 0 :(得分:2)

这个怎么样?

选项2:

begin tran;
delete from tablea where exists (select 1 from tableb where tablea.id=tableb.id);
insert into tablea select * from tableb;
commit tran;

选项3:

begin tran;
delete from tableb where exists (select 1 from tablea where tablea.id=tableb.id);
insert into tablea select * from tableb;
commit tran;

至于性能,只要tablea(大表)中的id字段被索引,你应该没问题。

答案 1 :(得分:0)

为什么你声称他想要合并时使用Upserts? SQL 2008中的MAREG更快,更高效。

我会让合并处理差异。