代码之家  ›  专栏  ›  技术社区  ›  ZombieSheep

仅当SQL Server中满足某个条件时触发

  •  25
  • ZombieSheep  · 技术社区  · 16 年前

    我希望这是一个足够简单的问题,对于任何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
    

    如果属性colum值以特定字符串(例如“nohist_uu”)作为前缀,我希望能够添加一些逻辑来停止创建记录。

    鉴于我几乎没有使用触发器的经验,我想知道如何最好地实现这一点……我试过一个WHERE子句,如下所示

    where I.Attribute NOT LIKE 'NoHist_%'
    

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

    如果您能提供任何帮助,我们将不胜感激。


    好的-正如CadeRoux预测的那样,这在多个更新中失败得很厉害。我要采取一种新的方法来解决这个问题。有人有其他建议吗?


    伙计们-请在这里教我…为什么在这个场景中左()比喜欢更可取?我知道我已经接受了答案,但我想知道我的教育。

    7 回复  |  直到 12 年前
        1
  •  39
  •   Joel Coehoorn    12 年前

    鉴于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
    
        2
  •  6
  •   Matty    16 年前

    这个怎么样?

    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
    
        3
  •  5
  •   Cade Roux    16 年前

    这个 _ 字符也是一个通配符,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
  •  4
  •   HLGEM    16 年前

    你的where条款应该有效。我不知道为什么不这样做。让我来告诉你,我该如何解决在何处条款的问题,因为它可能对你的未来有所帮助。

    当我创建触发器时,我从查询窗口开始创建一个名为插入(和或删除)的临时表,其中包含表中的所有列。然后我用典型值填充它(总是多个记录,我尝试在值中命中测试用例)

    然后我编写触发器逻辑,我可以测试它而不需要它实际在触发器中。在像WHERE子句这样的情况下,我可以通过注释插入来查看select返回的内容,从而轻松地进行测试。然后我可能很容易就能看出问题出在哪里。我向您保证,如果正确地编写了Clasue,它们在触发器中的作用是什么。

    一旦我知道代码在所有情况下都能正常工作,我就用inserted替换inserted,并在其周围添加create触发器代码和voila,这是一个测试过的触发器。

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

        5
  •  1
  •   QuintessentialSolutions    14 年前
    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
    
        6
  •  -1
  •   Daniel M    16 年前

    使用like将为您提供定义字符串其余部分应该是什么样子的选项,但如果规则只是以“nohist”开头,则并不重要。

        7
  •  -1
  •       15 年前

    对于一般的触发器,需要使用光标来处理多行的插入或更新。例如:

    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中)是一个巨大的难题,我完全避免使用它们。