T-SQL仅当其他值实际更改时,如何设置不带触发器的修改日期

时间:2014-12-08 16:39:56

标签: sql-server tsql

我的总体目标是仅在"部件"上更新[StandardUnitCost]字段。需要更新,同时仅在相同的行上更新[DateUpdated]字段。我使用的工具只通过匹配[DateUpdated]列来同步数据,因此重要的是它只会在[StandardUnitCost]也更新的行上发生更改。重要的是两者都发生,并且只在同一行上发生。如果[StandardUnitCost]字段将使用与其当前具有的值相同的值进行更新,则该值未更改,并且[DateUpdated]字段应更新。

我目前将此作为两个单独的更新语句,需要帮助将它们组合在一起。

Update [mas_wgd].[dbo].[CI_Item]
  Set dateupdated = CASE
   WHEN StandardUnitCost < AverageUnitCost then convert (date, GETDATE())
   WHEN (AverageUnitCost + 2) >= 22.0
    AND standardunitcost > (AverageUnitCost + 2.000000) then convert (date, GETDATE())
   When StandardUnitCost < 22.000000
    And StandardUnitCost > 0 then convert (date, GETDATE())
  Else dateupdated
end
Where ProductLine IN ('A010', 'A020', 'A030', 'A040', 'A050', 'A060', 'A070', 'A080',
      'A090', 'A100', 'A110', 'A120', 'A130', 'A130', 'A140', 'A150', 'A200', 'A250',
      'A300', 'A350', 'A400', 'A450', 'A500', 'A550', 'A600', 'AGNC', 'C010', 'C020',
      'C030', 'C040', 'C050', 'C060', 'C070', 'C080', 'C090', 'C100', 'C110', 'C120',
      'C130', 'C130', 'C140', 'C150', 'C200', 'C250', 'C300', 'C350', 'C400', 'C450',
      'C500', 'C550', 'C600', 'CGNC')


Update [mas_wgd].[dbo].[CI_Item]
 Set Standardunitcost = CASE
  WHEN (AverageUnitCost between 0.010000 and 22.000000) Then  22.00000 
  WHEN AverageUnitCost > 22.000000 then AverageUnitCost + 2.000000
 Else StandardUnitCost 
end
Where ProductLine IN ('A010', 'A020', 'A030', 'A040', 'A050', 'A060', 'A070', 'A080',
      'A090', 'A100', 'A110', 'A120', 'A130', 'A130', 'A140', 'A150', 'A200', 'A250',
      'A300', 'A350', 'A400', 'A450', 'A500', 'A550', 'A600', 'AGNC', 'C010', 'C020',
      'C030', 'C040', 'C050', 'C060', 'C070', 'C080', 'C090', 'C100', 'C110', 'C120',
      'C130', 'C130', 'C140', 'C150', 'C200', 'C250', 'C300', 'C350', 'C400', 'C450',
      'C500', 'C550', 'C600', 'CGNC')

2 个答案:

答案 0 :(得分:3)

通过CTE执行此操作将允许您指定一次公式并使用它来触发两个字段的更新:

SET NOCOUNT ON;
SET ANSI_NULLS ON;

DECLARE @Test TABLE (ID INT NOT NULL IDENTITY(1, 1),
                     AverageUnitCost INT NULL,
                     StandardUnitCost INT NULL,
                     ModifiedDate DATETIME,
                     WasUpdated BIT NULL);
INSERT INTO @Test VALUES (5, 8, GETDATE(), 0);
INSERT INTO @Test VALUES (15, 11, GETDATE(), 0);
INSERT INTO @Test VALUES (12, 35, GETDATE(), 0);
INSERT INTO @Test VALUES (22, 47, GETDATE(), 0);

SELECT * FROM @Test;

;WITH cte AS
(
  SELECT tmp.ID,
         tmp.StandardUnitCost,
         tmp.ModifiedDate,
         tmp.WasUpdated,
         CASE WHEN tmp.AverageUnitCost BETWEEN 10 AND 20 THEN 22
              WHEN tmp.AverageUnitCost > 20 THEN (tmp.AverageUnitCost + 2)
              ELSE tmp.StandardUnitCost
         END AS [NewValue]
  FROM @Test tmp
  --WHERE ProductLine IN ('A010'...) -- this is part of the real table so uncomment
)
UPDATE tab
SET    tab.StandardUnitCost = tab.NewValue,
       tab.ModifiedDate = GETDATE(),
       tab.WasUpdated = 1 -- only here to clearly indicate that the row was updated
FROM   cte tab
WHERE  tab.StandardUnitCost <> tab.NewValue;

SELECT * FROM @Test;

[WasUpdated]字段仅在那里,因为语句运行得足够快,而且在更新的行上[ModifiedDate]字段的值可能没有差异。

答案 1 :(得分:2)

我相信您可以通过将StandardCost更新的条件移到WHERE子句来简化查询,在这种情况下,您将确保匹配的行将被更新,因此也可以放心地加时间戳dateupdated列同时显示:

Update [mas_wgd].[dbo].[CI_Item]
  Set dateupdated = convert (date, GETDATE()),
  Standardunitcost = 
    CASE
       WHEN (AverageUnitCost between 0.010000 and 22.000000) Then  22.00000 
       WHEN AverageUnitCost > 22.000000 then AverageUnitCost + 2.000000
    END -- CASE
Where ProductLine IN ('A010', ...  'CGNC')
AND  (AverageUnitCost > 0.010000);

CASE上的StandardUnitCost更新之间的共同主题似乎是AverageUnitCost大于0.010000时会更新。

这也可以避免对Set dateupdated = dateupdatedStandardunitcost = Standardunitcost

表单进行冗余更新