【问题标题】:SQL Server : update trigger seeming to affect wrong columnSQL Server:更新触发器似乎影响了错误的列
【发布时间】:2018-09-29 17:57:18
【问题描述】:

感谢收看。我正在尝试编写一个 SQL Server 触发器,当添加包含日期信息的新记录时,会将星期几添加到 DayOfWeek 列。这是我的表格,列按顺序排列:

食物表:

FoodName **varchar(20)**  
CategoryID (FK) **int**  
Price **smallmoney**  
StoreID (FK) **int**  
Date **datetime**  
DayOfWeek **varchar(9)**  
ShopperID (FK) **int**  
Week **int**  

这是我写的触发器:

-- Create a trigger to update day of the week when a record is inserted  
CREATE TRIGGER DOW  
ON Food  
FOR INSERT  
AS  
BEGIN  
    -- Declare a variable to hold the date ID  
    DECLARE @dateID DATETIME

    -- Get the date from the new record and store it in @dateID  
    SELECT @dateID = Date FROM Food  

    -- Insert day of the week based on the inserted date  
    INSERT INTO Food (DayOfWeek)  
        SELECT DATENAME(dw, @dateID)  
END  
GO  

SQL Server 似乎接受了这个过程,但是当我运行另一个过程来插入新记录时,我得到了这个错误:

消息 515,级别 16,状态 2,过程 DOW,第 8 行 [批处理开始第 21 行]
无法将值 NULL 插入“周”列、表 *******;列不允许空值。插入失败。

我不确定为什么这个触发器会影响“周”列。代码应采用为 Date 输入的值并使用 DATENAME(dw,...) 函数返回星期几,该日期应进入 DayOfWeek 列。我写了一个存储过程,它接受一个日期作为输入,并将相应的星期几插入到记录中,它工作得很好,但是这个触发器似乎不想合作。我被难住了!

【问题讨论】:

  • food.week 似乎是声明NOT NULL。当您插入food 而不指定week 的值时,您在触发器中执行此操作,这会导致错误或您实际遇到的错误。
  • dayofweek 可能还有weektoo,如果这是日历周数,则全部取决于我猜的日期,因此根本不应该在该表中。或者,如果您坚持将它们放在表中,您可能希望查看计算列,而不是使用触发器。
  • 除 DayOfWeek 之外的所有列都不为 NULL。问题是,当我运行我的 INSERT 过程时,为每一列提供了一个值,除了 DayOfWeek,它应该从这个触发器中获取它的值。 Week 列根本不受此触发器的影响。
  • 你的表的主键是什么?

标签: sql-server triggers sql-insert


【解决方案1】:

触发器的作用:

  • 它从您的表(返回的最后一个)中获取Date,这不一定是最后插入的值。
  • 它尝试插入仅指定 DayOfWeekDayOfWeek 的新记录。
  • 失败,因为至少还必须指定 Week

我猜你想为插入的行更新DayOfWeek 的值。为此,必须有一种方法可以通过知道插入行的值来识别 Food 表中需要更新的行。为了确保更新正确的行,应该有一个主键可以让您识别它们。你肯定有这样一个主键,我猜它的名字是FoodID,所以你可能想这样做:

CREATE TRIGGER DOW ON Food
FOR INSERT
AS
BEGIN
    SET NOCOUNT ON;
    -- update the day of the week for the inserted rows
    UPDATE Food
        SET [DayOfWeek] = DATENAME(dw, f.[Date])
    FROM Food f
        INNER JOIN inserted i ON f.FoodID = i.FoodID
END
GO

【讨论】:

    【解决方案2】:

    您的触发器存在一些重大问题。在触发器中,有一个插入表(关于插入和更新)和一个已删除表(关于删除和更新)。您应该使用此表的信息来了解需要更新哪些记录。

    This is bad because a trigger can have multiple rows
    This SQL simply will not work correctly if you insert multiple rows.
    DECLARE @dateID DATETIME
    SELECT @dateID = Date FROM Food  
    
    This SQL is trying to insert a new row which is causing your NULL error
    It is not trying to update the row you are inserting
    INSERT INTO Food (DayOfWeek)  
        SELECT DATENAME(dw, @dateID)  
    

    它需要是一个 INSTEAD OF 触发器以避免列上的空约束。 Wolfgang 的回答仍然会导致空约束错误,因为在插入数据之后触发器运行之后。 INSTEAD OF 触发器将代替实际插入运行。

    CREATE TRIGGER DOW ON Food
    INSTEAD OF INSERT
    AS
    BEGIN
        SET NOCOUNT ON;
        -- update the day of the week for the inserted rows
    
        INSERT INTO Food (FoodName,CategoryID,Price,StoreID,[Date],ShopperID,[Week],[DayOfWeek])
            SELECT
                FoodName,CategoryID,Price,StoreID,[Date],ShopperID,[Week],DATENAME(dw, [Date]) AS [DayOfWeek]
            FROM inserted
    END
    GO
    

    就个人而言,我认为存储星期和星期几是一个坏主意。您已经有一个可以派生该信息的值(日期)。每当您有多个列本质上是重复数据时,您都会遇到维护难题。

    【讨论】:

      猜你喜欢
      • 2014-10-09
      • 1970-01-01
      • 2011-10-23
      • 2011-10-23
      • 1970-01-01
      • 1970-01-01
      • 2011-06-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多