【发布时间】:2010-10-22 05:13:21
【问题描述】:
我有一个使用相当大的表(数百万行,大约 30 列)的 Web 应用程序。我们称它为 TableA。在这 30 列中,该表有一个名为“id”的主键和一个名为“campaignID”的列。
作为应用程序的一部分,用户可以上传与新“活动”相关的新数据集。
这些数据集的结构与 TableA 相同,但通常只有大约 10,000-20,000 行。
新数据集中的每一行都有一个唯一的“id”,但它们都将共享同一个campaignID。换句话说,用户正在为一个新的“campaign”加载完整的数据,因此所有 10,000 行都具有相同的“campaignID”。
通常,用户正在上传新广告系列的数据,因此表 A 中没有具有相同广告系列 ID 的行。由于“id”对于每个广告系列都是唯一的,因此每行新数据的 id 在 TableA 中都是唯一的。
但是,在极少数情况下,当用户尝试为数据库中已存在的“广告系列”加载一组新行时,要求首先从 TableA 中删除该广告系列的所有旧行,然后再插入新数据集中的新行。
所以,我的存储过程很简单:
- 将新数据批量插入临时表 (#tableB)
- 删除 TableA 中具有相同活动 ID 的所有现有行
- 插入表 A ([columns]) 从 #TableB 中选择 [columns]
- 删除#TableB
这工作得很好。
但新要求是在用户上传新数据以处理“重复”时为用户提供 3 个选项 - 用户正在为已在 TableA 中的活动上传数据的实例。
- 删除 TableA 中具有相同活动 ID 的所有数据,然后插入 #TableB 中的所有新数据。 (这是旧行为。使用此选项,它们将永远不会重复。)
- 如果#TableB 中的一行与TableA 中的行具有相同的ID,则使用#TableB 中的行更新TableA 中的该行(实际上,这是用新数据“替换”旧数据)
- 如果#TableB 中的一行与TableA 中的行具有相同的ID,则忽略#TableB 中的该行(本质上,这是保留原始数据,而忽略新数据)。
用户无法逐行选择此项。她选择如何合并数据,并将此逻辑应用于整个数据集。
在我使用 MySQL 开发的类似应用程序中,我使用了“LOAD DATA INFILE”函数,并带有“REPLACE”或“IGNORE”选项。但我不知道如何使用 SQL Server/T-SQL 来做到这一点。
任何解决方案都需要足够高效以处理 TableA 有数百万行,而#TableB(新数据集)可能有 10k-20k 行的事实。
我在 Google 上搜索了类似“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
【问题讨论】:
-
获取新日期相当容易,您可以在带有左连接的集合中完成更新也应该相当简单,因为您也可以在集合中完成棘手的部分是交易正确,它的complicated enough 正确处理 1 行。