2014-08-28 35 views
2

我想使用内部联接对表进行一种“批量更新”。这是它的工作原理。在T-SQL中,如何确保只有在更新同一UPDATE语句中的所有其他列值后才更新列值?

有两个问题表,其中之一正在更新。我会打电话给正在更新的OriginalTable和另一个UpdateData

OriginalTableUpdateData都包含名为Id的PK列,我们稍后再加入。 OriginalTable包含许多其他列,所有这些列都是nvarchars,我会将这些列称为数据列。最后,OriginalTable还包含一个校验和列,我希望在给定行的数据列中包含字符串连接数据的SHA1哈希值。 UpdateData包含OriginalTable中的数据列子集,这就是用来指定将OriginalTable中的数据更新为的内容。

如果UpdateData中的值是非空字符串或NULL,那么我想用该值更新OriginalTable中的对应行。如果该值为空字符串,那么我不想修改OriginalTable行的值。

比方说,在OriginalTable的数据列有:FirstNameLastNameMIAge。假设UpdateData中的数据列是:FirstNameLastName,Age。这基本上意味着我们正在更新除了MI之外的所有信息。

我能完成这次更新这个SQL:

UPDATE T 
SET FirstName = CASE UD.FirstName WHEN '' THEN T.FirstName ELSE UD.FirstName END, 
    LastName = CASE UD.LastName WHEN '' THEN T.LastName ELSE UD.LastName END, 
    Age = CASE UD.Age WHEN '' THEN T.Age ELSE UD.Age END 
FROM #OriginalTable T 
INNER JOIN #UpdateData UD 
    ON T.Id = UD.Id; 

这点不错。现在,我面临的挑战是,当涉及到更新行的Checksum值时,我不知道如何保证散列计算只会在其他行被更新后才会发生。我应该提到,校验和计算必须在同一个语句中进行。我想要做这样的事情:

UPDATE T 
SET FirstName = CASE UD.FirstName WHEN '' THEN T.FirstName ELSE UD.FirstName END, 
    LastName = CASE UD.LastName WHEN '' THEN T.LastName ELSE UD.LastName END, 
    Age = CASE UD.Age WHEN '' THEN T.Age ELSE UD.Age END, 
    Checksum = CONVERT(varchar(40), HASHBYTES('SHA1', T.FirstName + T.LastName + T.MI + T.Age), 2) 
FROM #OriginalTable T 
INNER JOIN #UpdateData UD 
    ON T.Id = UD.Id; 

我需要在更新后计算OriginalTable与值校验列的值。我怎样才能在同一个UPDATE语句中完成这个散列计算,保证在其他列更新后计算它的数据?

+1

你就不能让它两种说法,但在交易中换呢?您是否有理由在单一声明中完成?这仅仅是为了原子性吗? – Charleh 2014-08-28 15:50:21

+1

更新不是整个系列的事件。它发生在一次。如果你想这样做,你需要在你的HASHBYTES函数中添加所有的case表达式或者进行第二次更新。你有它编码你的HASHBYTES的方式将使用当前值,而不是新的价值将是什么。 – 2014-08-28 15:51:11

+3

老实说,我会考虑让你的Checksum成为一个计算列。这将避免你必须与它搏斗。 – 2014-08-28 15:52:21

回答

0

你可以尝试这样的事情(未经测试):

UPDATE T 
SET FirstName = UD.FirstName, 
    LastName = UD.LastName, 
    Age = UD.Age, 
    Checksum = CONVERT(varchar(40), HASHBYTES('SHA1', UD.FirstName + UD.LastName + T.MI + UD.Age), 2) 
FROM #OriginalTable T 
INNER JOIN (
    SELECT T1.Id, 
      CASE UD1.FirstName WHEN '' THEN T1.FirstName ELSE UD1.FirstName END AS FirstName, 
      CASE UD1.LastName WHEN '' THEN T1.LastName ELSE UD1.LastName END AS LastName, 
      CASE UD1.Age WHEN '' THEN T1.Age ELSE UD1.Age END AS Age 
     FROM #OriginalTable T1 
     INNER JOIN #UpdateData UD1 ON T1.Id = UD1.Id) AS UD 
    ON T.Id = UD.Id;