仅在SQL Server中满足条件时才触发

时间:2008-11-11 13:45:48

标签: sql-server triggers

我希望这对任何SQL人员来说都是一个简单的问题......

我们有一个包含系统配置数据的表,它通过触发器与历史表绑定,因此我们可以跟踪谁更改了什么,何时更改。

我需要在此表中添加另一个值,但它会经常从代码中更改,并且要求我们不跟踪它的历史记录(我们不希望阻塞该表每天有数千个更新。

目前,我们的触发器有点像这样......

CREATE TRIGGER 
    [dbo].[SystemParameterInsertUpdate]
ON 
    [dbo].[SystemParameter]
FOR INSERT, UPDATE 
AS
  BEGIN
    SET NOCOUNT ON
      INSERT INTO SystemParameterHistory 
      (
        Attribute,
        ParameterValue,
        ParameterDescription,
        ChangeDate
      )
    SELECT
      Attribute,
      ParameterValue,
      ParameterDescription,
      ChangeDate
    FROM Inserted AS I
END

如果Attribute colum值以特定字符串作为前缀(例如“NoHist _”),我希望能够添加一些逻辑来阻止它创建记录

鉴于我几乎没有使用触发器的经验,我想知道如何最好地实现这个...我已经尝试过如下的where子句

where I.Attribute NOT LIKE 'NoHist_%'

但它似乎不起作用。该值仍会复制到历史记录表中。

您可以提供任何帮助。


好的 - 正如Cade Roux预测的那样,这次失败引起了多次更新。我将不得不对此采取新方法。有人有任何其他建议吗?


伙计们 - 请在这里教育我......为什么LEFT()在这种情况下会优于LIKE?我知道我接受了答案,但我想知道我自己的教育。

7 个答案:

答案 0 :(得分:39)

鉴于WHERE子句不起作用,可能会这样:

CREATE TRIGGER 
    [dbo].[SystemParameterInsertUpdate]
ON 
    [dbo].[SystemParameter]
FOR INSERT, UPDATE 
AS
  BEGIN
    SET NOCOUNT ON

      If (SELECT Attribute FROM INSERTED) LIKE 'NoHist_%'
      Begin
          Return
      End

      INSERT INTO SystemParameterHistory 
      (
        Attribute,
        ParameterValue,
        ParameterDescription,
        ChangeDate
      )
    SELECT
      Attribute,
      ParameterValue,
      ParameterDescription,
      ChangeDate
    FROM Inserted AS I
END

答案 1 :(得分:6)

这个怎么样?

CREATE TRIGGER 
[dbo].[SystemParameterInsertUpdate]
ON 
[dbo].[SystemParameter]
FOR INSERT, UPDATE 
AS
BEGIN
SET NOCOUNT ON
  IF (LEFT((SELECT Attribute FROM INSERTED), 7) <> 'NoHist_') 
  BEGIN
      INSERT INTO SystemParameterHistory 
      (
        Attribute,
        ParameterValue,
        ParameterDescription,
        ChangeDate
      )
    SELECT
      Attribute,
      ParameterValue,
      ParameterDescription,
      ChangeDate
   FROM Inserted AS I
END
END

答案 2 :(得分:5)

你的where子句应该有效。我不知道为什么没有。让我告诉你我如何通过where子句找出问题,因为它可能对你的未来有所帮助。

当我创建触发器时,我从查询窗口开始,创建一个名为#inserted(和/或#leleted)的临时表,其中包含表的所有列。然后我用典型值(总是多个记录,我尝试在值中点击测试用例)来播放它

然后我编写了我的触发器逻辑,我可以在没有实际处于触发器中的情况下进行测试。在你的where子句没有做到预期的情况下,我可以通过注释插入来轻松测试,看看select返回了什么。那么我可能很容易就能看出问题所在。我向你保证,如果正确写入,那么clasues在触发器中的作用是什么。

一旦我知道代码适用于所有情况,我将全局替换为插入的#inserted并在其周围添加创建触发器代码,并且这是一个经过测试的触发器。

正如我在评论中所说,我担心您选择的解决方案在多记录插入或更新中无法正常工作。应该始终写入触发器,因为您无法预测它们是否以及何时发生(并且它们最终会在每个表中发生。)

答案 3 :(得分:5)

_字符也是一个通配符,BTW,但我不确定为什么这不适合你:

CREATE TRIGGER 
    [dbo].[SystemParameterInsertUpdate]
ON 
    [dbo].[SystemParameter]
FOR INSERT, UPDATE 
AS
  BEGIN
    SET NOCOUNT ON
      INSERT INTO SystemParameterHistory 
      (
        Attribute,
        ParameterValue,
        ParameterDescription,
        ChangeDate
      )
    SELECT
      I.Attribute,
      I.ParameterValue,
      I.ParameterDescription,
      I.ChangeDate
    FROM Inserted AS I
    WHERE I.Attribute NOT LIKE 'NoHist[_]%'
END

答案 4 :(得分:1)

CREATE TRIGGER
    [dbo].[SystemParameterInsertUpdate]
ON 
    [dbo].[SystemParameter]
FOR INSERT, UPDATE 
AS
  BEGIN
    SET NOCOUNT ON 

    DECLARE @StartRow int
    DECLARE @EndRow int
    DECLARE @CurrentRow int

    SET @StartRow = 1
    SET @EndRow = (SELECT count(*) FROM inserted)
    SET @CurrentRow = @StartRow

    WHILE @CurrentRow <= @EndRow BEGIN

        IF (SELECT Attribute FROM (SELECT ROW_NUMBER() OVER (ORDER BY Attribute ASC) AS 'RowNum', Attribute FROM inserted) AS INS WHERE RowNum = @CurrentRow) LIKE 'NoHist_%' BEGIN

            INSERT INTO SystemParameterHistory(
                Attribute,
                ParameterValue,
                ParameterDescription,
                ChangeDate)
            SELECT
                I.Attribute,
                I.ParameterValue,
                I.ParameterDescription,
                I.ChangeDate
            FROM
                (SELECT Attribute, ParameterValue, ParameterDescription, ChangeDate FROM (
                                                                                            SELECT ROW_NUMBER() OVER (ORDER BY Attribute ASC) AS 'RowNum', * 
                                                                                            FROM inserted)
                                                                                    AS I 
            WHERE RowNum = @CurrentRow

        END --END IF

    SET @CurrentRow = @CurrentRow + 1

    END --END WHILE
END --END TRIGGER

答案 5 :(得分:-1)

使用LIKE将为您提供定义字符串其余内容的选项,但如果规则只是以“NoHist_”开头,则无关紧要。

答案 6 :(得分:-1)

对于通常的触发器,您需要使用游标来处理多行的插入或更新。例如:

DECLARE @Attribute;
DECLARE @ParameterValue;
DECLARE mycursor CURSOR FOR SELECT Attribute, ParameterValue FROM inserted;
OPEN mycursor;
FETCH NEXT FROM mycursor into @Attribute, @ParameterValue;
WHILE @@FETCH_STATUS = 0
BEGIN

If @Attribute LIKE 'NoHist_%'
      Begin
          Return
      End

etc.

FETCH NEXT FROM mycursor into @Attribute, @ParameterValue;
END

触发器,至少在SQL Server中,是一个巨大的痛苦,我完全避免使用它们。