更新触发器使用的日期

Update DateUsed by trigger

我正在尝试使用另一个 table 的触发器更新 table。我认为这将是一个非常简单的查询,但我最初提出的查询不起作用,我不明白为什么。

CREATE TABLE [dbo].[Vehicle](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [plate] [nvarchar](50) NOT NULL,
    [name] [nvarchar](50) NOT NULL,
    [dateUsed] [datetime] NULL
)

CREATE TABLE [dbo].[Transaction](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [vehicleId] [int] NOT NULL,
    [quantity] [float] NOT NULL,
    [dateTransaction] [datetime] NOT NULL,
)

添加交易后,我希望更新车辆table。如果添加的 dateTransaction 晚于 dateUsed,则应对其进行更新,以便 dateUsed 字段始终包含该特定车辆的最新日期。

我认为这个触发器应该可以解决问题..但它没有:

UPDATE [Vehicle] 
SET [dateUsed] = 
    CASE 
        WHEN [dateUsed] < [Transaction].[dateTransaction] 
            OR [dateUsed] IS NULL
            THEN [Transaction].[dateTransaction] 
        ELSE [dateUsed] 
    END
FROM [Transaction]
WHERE [Vehicle].[id]=[Transaction].[vehicleId]

我觉得不错...它应该遍历所有新插入的记录并更新 dateUsed 字段。如果 dateTransaction 较新,则使用那个。如果不是。使用当前的。但我似乎遗漏了一些东西,因为它没有更新到最新日期。它确实匹配该特定车辆的其中一项交易,但不匹配最新的交易。

有效的查询:

UPDATE [Vehicle] 
SET [dateUsed] = InsertedPartitioned.[dateTransaction]
FROM [Vehicle]
LEFT JOIN (
    SELECT 
        [vehicleId],
        [dateTransaction],
        ROW_NUMBER() OVER(PARTITION BY [VehicleId] ORDER BY [dateTransaction] DESC) AS RC
    FROM [Inserted]) AS InsertedPartitioned 
    ON InsertedPartitioned.RC=1 
    AND InsertedPartitioned.[vehicleId]=[Vehicle].[id]
WHERE InsertedPartitioned.[vehicleId] IS NOT NULL
    AND ([Vehicle].[dateUsed] IS NULL 
        OR InsertedPartitioned.[dateTransaction] > [Vehicle].[dateUsed]);

所以我有一个可行的解决方案,它甚至可能会变得更好(没有用大的插入物计时)但是它让我不知道为什么第一个它不起作用!

任何人都可以 'enlighten me'?

why the first it not working

由于 Microsoft 对 UPDATE 的扩展使用了 FROM 子句:

Use caution when specifying the FROM clause to provide the criteria for the update operation. The results of an UPDATE statement are undefined if the statement includes a FROM clause that is not specified in such a way that only one value is available for each column occurrence that is updated, that is if the UPDATE statement is not deterministic.

(我的重点)。

也就是说,如果 inserted 中的不止一行与 Vehicle 中的同一行相匹配,则它是未定义的 哪一个 行将用于应用update - SET 子句中的所有计算都是计算 "as if" 它们都是并行计算的 - 所以第二次尝试更新同一行不会观察到第一次尝试的结果 - DateUsed列当前可观测值始终为原始值


在 ANSI 标准 SQL 中,您必须在不使用 FROM 扩展的情况下编写 UPDATE,因此必须编写相关的子查询,例如:

UPDATE [Vehicle] 
SET [dateUsed] = COALESCE((SELECT dateUsed FROM inserted i
         WHERE i.VehicleId = Vehicle.Id and
         (i.dateUsed > Vehicle.DateUsed or
          Vehicle.DateUsed IS NULL),
     dateUsed)
WHERE [id] IN (select [vehicleId] FROM inserted)

在同样的情况下,如果子查询返回多个值(COALESCE 中的值,而不是 IN 中的值),则很好地给出一个错误,并且从而为您提供有关它为何不起作用的线索。

但是,不可否认,FROM 扩展很有用 - 我只是希望它能针对这种情况触发警告。