【问题标题】:SQL Bulk Upload, Merge and Delete recordsSQL 批量上传、合并和删除记录
【发布时间】:2015-04-05 17:20:26
【问题描述】:

我正在创建一个 ASP.net Web 应用程序,它接收来自用户的 CSV 文件,将文件上传到服务器,将数据批量复制到 TempHoldingTable。然后代码调用包含Merge 语句的存储过程,将TempHoldingTable 中的数据复制到相关的多个表中。我正在使用 SQL Server 2008 R2。

我在存储过程中有多个Merge 语句,我在下面只复制了一个:

MERGE Client AS C
USING (SELECT ClientID, Value1, Value2, Value3, Row_Number() Over (PARTITION BY ClientID order by Date desc) as Rno 
       FROM TempHoldingTable) AS T ON (C.ClientID = T.ClientID)

WHEN NOT MATCHED BY TARGET AND T.Rno = 1
    THEN 
        INSERT(ClientID, Value1, Value2, Value3)
        VALUES(T.ClientID, Value1, Value2, Value3)                      
        OUTPUT $action, inserted.*, deleted.*;

CSV 文件每个月都会上传,所以假设第一个文件是在 2014 年 1 月上传的,它有以下数据:

ClientID Value1 Value2 Value3
 111      abc    def    ghi
 222      jkl    mno    pqr

然后用户在 2014 年 2 月上传了第二个文件,它有以下数据:

ClientID Value1 Value2 Value3
 111      aaa    bbb    ghi
 222      jkl    mno    pqr
 333      sss    ttt    uuu

Merge 例程将更新 ClientID 111 的客户端表,因为 value1 和 value2 已更改,保持 ClientID 222 不变,并为 ClientID 333 插入新行。

我的问题是,如果用户决定删除 2014 年 2 月的文件,我如何跟踪和恢复由于 2014 年 2 月上传而导致的更改,以便客户端表包含与 2014 年 1 月上传后相同的数据。

请注意,每次上传都需要进行此跟踪,这样每当用户删除文件时,数据库就会恢复到与上个月相同的位置。

我的第二个问题是如果存在 ClientID 并且任何列的值与前一个不同,如何修改 Merge 语句以更新值。

感谢您耐心阅读所有这些内容,我们将不胜感激。

【问题讨论】:

  • 因此,如果用户在哪里删除 Feb2014 文件,您将恢复到 2014 年 1 月的设置,然后重播 3 月、4 月、5 月等的文件……对吗?
  • 用户只能以相反的顺序删除文件,所以如果最后一个文件是在三月上传的,那么他们可以在删除二月文件之前删除三月文件。当他们删除 3 月文件时,数据将恢复为 2 月文件上传时的状态。当他们删除 2 月文件时,数据将恢复为 1 月。一旦我们有了 1 月数据,用户将被允许再次上传 2 月文件,然后是 3 月,依此类推。
  • 你的数据集有多大?
  • 每个文件可以包含 20K 到 30K 行和 100 多列。数据被批量复制到临时表,然后跨 8 个表移动。很多行将包含相同的数据,这就是我使用 Merge 表的原因,这样我就不需要更改这些记录的数据。

标签: sql merge sql-server-2008-r2 sqlbulkcopy


【解决方案1】:

问题 1 的答案: 根据您的数据大小,我认为设置跟踪机制 (Change tracking /CDC) 将是一种矫枉过正 (IMO)。您可能会设置一个过程(在应用文件之前)将 8 个表中的每一个表中的数据推送到另一组表(版本化数据集)中,该表基于月/年存储它。 如果用户决定删除特定的月份文件,请从版本化数据集中提取前一组并将其应用于活动表。

请记住为版本化数据集设置一个清除过程,否则它可能会随着时间的推移而变得相当大。

回答 Q2:您可以使用When Matched 子句

MERGE Client AS C
USING (SELECT ClientID, Value1, Value2, Value3, Row_Number() Over (PARTITION BY ClientID order by Date desc) as Rno 
       FROM TempHoldingTable) AS T ON (C.ClientID = T.ClientID)

WHEN NOT MATCHED BY TARGET AND T.Rno = 1
    THEN 
        INSERT(ClientID, Value1, Value2, Value3)
        VALUES(T.ClientID, Value1, Value2, Value3)                      
WHEN MATCHED 
        THEN UPDATE SET C.Value1 = T.Value1
        , C.Value2 = T.Value2
        , C.Value3 = T.Value#3
OUTPUT $action, inserted.*, deleted.*;

【讨论】:

  • 感谢您的回答,我想多想一点,明天再和同事谈谈,我喜欢单独版本化表的想法。出于好奇,跟踪机制将如何实施,我们是否应该决定走这条路?请注意,我们希望获得多个客户,因此如果我们有 10 个客户,那么每个客户每个月将上传一个文件(总共 10 个文件)。每个客户都有自己的数据,但将存储在一个数据库中,由 CustomerID 区分。如果我们获得 20 个客户,那么每个月将有 20 个文件。请指教。
  • 我已经和同事谈过了,我们想走您推荐的这条路线。由于每月上传的文件数量可能会迅速增加,因此除了清除之外,您是否设想过任何问题。您能否提供一些有关如何实施跟踪机制的信息?感谢您的帮助。
  • 对于 SQL server 跟踪机制,您首先阅读以下文章: 1. Change Tracking msdn.microsoft.com/en-us/library/bb933875.aspx 2: Change Data capture technet.microsoft.com/en-us/library/…
  • 'When Matched' 语句更新行,即使 value1 或 value2 或 value3 没有改变,是否可以仅在其中一个值与现有值不同时才执行更新语句?Q2,做我需要使用主键和/或 T.Rno=1,如 'When Matched AND T.Rno=1 And C.ClientID=T.ClientID?或者在匹配时使用 PK 是多余的。谢谢
猜你喜欢
  • 1970-01-01
  • 2020-08-17
  • 1970-01-01
  • 1970-01-01
  • 2021-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多