34

我希望这对于任何 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

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

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

where I.Attribute NOT LIKE 'NoHist_%'

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

您可以提供的任何帮助将不胜感激。


好的 - 正如 Cade Roux 所预测的那样,这在多次更新时都失败了。我将不得不采取一种新的方法来解决这个问题。请问有人有其他建议吗?


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

4

7 回答 7

48

鉴于 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
于 2008-11-11T14:04:13.387 回答
7

这个怎么样?

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
于 2008-11-11T14:08:36.843 回答
6

顺便说一句,该_字符也是通配符,但我不确定为什么这对您不起作用:

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
于 2008-11-11T19:07:25.053 回答
5

您的 where 子句应该有效。我不知道为什么没有。让我向您展示我如何解决 where 子句的问题,因为它可能对您未来有所帮助。

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

然后我编写我的触发器逻辑,我可以在它实际上不在触发器中的情况下进行测试。在像您的 where 子句没有达到预期效果的情况下,我可以通过注释掉插入来轻松测试,以查看选择返回的内容。然后我可能很容易就能看出问题所在。我向您保证,如果编写正确,哪些子句在触发器中起作用。

一旦我知道代码在所有情况下都能正常工作,我将 #inserted 全局替换为 insert 并在其周围添加创建触发器代码,瞧,一个经过测试的触发器。

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

于 2008-11-11T14:24:29.790 回答
2
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
于 2010-09-02T23:14:21.983 回答
-1

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

于 2008-11-11T15:06:43.400 回答
-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 中,是一个很大的痛苦,我完全避免使用它们。

于 2009-02-18T19:23:21.380 回答