【问题标题】:In T-SQL, how can I guarantee that a column value is updated only after all other column values in the same UPDATE statement have been updated?在 T-SQL 中,如何保证只有在同一 UPDATE 语句中的所有其他列值都已更新后才更新列值?
【发布时间】:2014-10-22 13:26:06
【问题描述】:

我想使用内部联接对表进行某种“批量更新”。以下是它的工作原理。

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

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

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

假设OriginalTable中的数据列是:FirstNameLastNameMIAge。假设UpdateData 中的数据列是:FirstNameLastNameAge。这基本上意味着我们正在更新除 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;

这很好。现在,我面临的挑战是,在更新一行的校验和值时,我不知道如何保证只有在其他行首先更新后才会进行哈希计算。我应该提到,校验和计算发生在同一个语句中是很重要的。我想做这样的事情:

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 语句中完成这个哈希计算,保证在其他列更新后计算它的数据?

【问题讨论】:

  • 你不能只写两个语句,而是将它们包装在一个事务中吗?您是否有理由需要在单个语句中完成它?只是为了原子性吗?
  • 一次更新并不是一连串的事件。它同时发生。如果你想这样做,你需要在你的 HASHBYTES 函数中添加所有的 case 表达式或进行第二次更新。您对 HASHBYTES 进行编码的方式将使用当前值,而不是新值。
  • 老实说,我会考虑将您的校验和设为计算列。这将避免你不得不与它搏斗。

标签: sql sql-server tsql join


【解决方案1】:

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

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;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-13
    • 2021-03-29
    • 2012-02-22
    相关资源
    最近更新 更多