【问题标题】:Adding conditions to Triggers in SQL Server在 SQL Server 中向触发器添加条件
【发布时间】:2018-10-02 04:59:59
【问题描述】:

我的 SQL Server 数据库中有这些表:

CREATE TABLE weather 
(
     weatherId integer Identity(1,1) primary key,
     weatherDate datetime,
     rainout BIT,
     temperature float,
     inchesOfRain float
)

CREATE TABLE weather_audit 
(
     weatherAuditId integer Identity(1,1) primary key,
     weatherId integer,
     date datetime,
     rainout BIT,
     temperature float,
     inchesOfRain float
)

CREATE TABLE maintenance 
(
     maintenanceId integer Identity(1,1) primary key,
     maintenanceDescription nvarchar(100),
     dateRequested datetime,
     dateResolved datetime,
     currentStatus nvarchar(20),
     estimatedCost decimal,
)

CREATE TABLE maintenence_audit
(
     mainteneceAuditId integer Identity(1,1) primary key,
     maintenanceId integer,
     description nvarchar(100),
     dateRequested datetime,
     dateResolved datetime,
     currentStatus nvarchar(20),
     estimatedCost decimal,
     updatedOn datetime
)

我想设置一个触发器,当将一行插入到 inchesOfRain 大于 4 的天气表中时触发。这就是我现在所拥有的,但它不起作用:

CREATE TRIGGER tr_weather_ForInsertUpdate 
ON weather
FOR INSERT, UPDATE
AS
BEGIN
    SET NOCOUNT ON

    IF (SELECT TOP 1 inchesOfRain FROM weather) > 4
         INSERT INTO weather_audit (weatherId, weatherDate, rainout, temperature, inchesOfRain)
             SELECT
                 i.weatherId, i.weatherDate, i.rainout, i.temperature, i.inchesOfRain
             FROM 
                 Inserted AS I
END

所以如果我要插入这个

INSERT INTO dbo.weather (weatherDate, rainout, temperature, inchesOfRain)
VALUES ('4/21/2018', '0', '70', '6'); 

它将在weather 表和weather_audit 表中添加一行,因为雨量为 6 英寸

【问题讨论】:

    标签: sql sql-server database triggers


    【解决方案1】:

    您需要依赖您的 Inserted 伪表来决定是否向审计表中添加一行 - 试试这个:

    CREATE TRIGGER tr_weather_ForInsertUpdate 
    ON weather
    FOR INSERT, UPDATE
    AS
    BEGIN
        SET NOCOUNT ON
    
        INSERT INTO weather_audit (weatherId, weatherDate, rainout, temperature, inchesOfRain)
            SELECT
                i.weatherId, i.weatherDate, i.rainout, i.temperature, i.inchesOfRain
            FROM 
                Inserted AS I
            WHERE
                i.inchesOfRain > 4  -- just insert those rows with inchesOfRain > 4
    END
    

    【讨论】:

    • 所以我在这篇文章后不久最终做的是编辑我最初的 if 语句,因为我注意到我从错误的地方拉动了 insofrain 并将其更改为所以我在此之后不久最终做了什么帖子是这样的: IF (Select InchesOfRain FROM INSERTED) > 4 并保持 restr 相同,它工作得很好。这样做和你这样做有什么区别吗?
    【解决方案2】:

    你的触发器很好,它只需要是

    CREATE TRIGGER tr_weather_ForInsertUpdate 
    ON weather
    FOR INSERT, UPDATE
    AS
    BEGIN
        SET NOCOUNT ON
    
    --Modified Code Start
    DECLARE @inchesOfRain float
        
    SELECT @inchesOfRain = inchesOfRain FROM inserted
    
    
        IF @inchesOfRain > 4
        BEGIN
        ---------------Modified COde End
             INSERT INTO weather_audit (weatherId, weatherDate, rainout, temperature, inchesOfRain)
                 SELECT
                     i.weatherId, i.weatherDate, i.rainout, i.temperature, i.inchesOfRain
                 FROM 
                     Inserted AS I
         END
    END

    更新:Marc S 代码 sn-p 是完美的答案。

    【讨论】:

    • 您的触发器有一个 MAJOR 缺陷,即假定它会被 每行调用一次 - 事实并非如此。触发器将每条语句触发一次,因此如果您的INSERT 语句导致此触发器触发插入 25 行,您将触发触发器一次,但随后Inserted 伪表将包含 25 行。您的代码将在这 25 行中选择哪一行? SELECT @inchesOfRain = inchesOfRain FROM inserted - 它是不确定的,您将获得任意行,您将忽略所有其他行。您需要重写触发器以考虑到这一点!
    • 太棒了!完全有道理。非常感谢您指出这一点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-14
    • 1970-01-01
    • 2010-12-11
    • 1970-01-01
    相关资源
    最近更新 更多