Срабатывать, только если условие выполнено в SQL Server - PullRequest
25 голосов
/ 11 ноября 2008

Надеюсь, это достаточно простой вопрос для любого 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 задана конкретная строка (например, «NoHist _»)

Учитывая, что у меня почти нет опыта работы с триггерами, мне было интересно, как лучше всего это реализовать ... Я пробовал предложение where, подобное следующему

where I.Attribute NOT LIKE 'NoHist_%'

но, похоже, это не работает. Значение все еще копируется в таблицу истории.

Буду признателен за любую помощь, которую вы можете предложить.


ОК - как и предсказывал Cade Roux, этот эффект впечатляюще проваливается при нескольких обновлениях. Я собираюсь принять новый подход к этому. У кого-нибудь есть другие предложения, пожалуйста?


Ребята - Пожалуйста, расскажите мне здесь ... Почему LEFT () предпочтительнее LIKE в этом сценарии? Я знаю, что принял ответ, но я хотел бы знать, для моего собственного образования.

Ответы [ 7 ]

39 голосов
/ 11 ноября 2008

Учитывая, что предложение 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
6 голосов
/ 11 ноября 2008

Как насчет этого?

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
5 голосов
/ 11 ноября 2008

Символ _ также подстановочный знак, кстати, но я не уверен, почему это не сработало для вас:

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
5 голосов
/ 11 ноября 2008

Ваше предложение where должно сработать. Я в недоумении, почему это не так. Позвольте мне показать вам, как бы я выяснил проблему с предложением where, поскольку это может помочь вам в будущем.

Когда я создаю триггеры, я начинаю с окна запроса, создавая временную таблицу с именем #inserted (и или #deleted) со всеми столбцами таблицы. Затем я наполняю его типичными значениями (всегда несколько записей, и я пытаюсь использовать контрольные примеры в значениях)

Затем я пишу свою логику триггеров, и я могу тестировать без ее фактического нахождения в триггере. В случае, когда ваше предложение where не соответствует ожидаемому, я мог бы легко проверить, закомментировав вставку, чтобы увидеть, что возвращал select. Тогда я, вероятно, легко смогу увидеть, в чем проблема. Уверяю вас, что когда классы работают в триггерах, если они написаны правильно.

Как только я узнаю, что код работает правильно для всех случаев, я глобально заменяю #inserted вставленным и добавляю код триггера создания вокруг него, и вуаля, проверенный триггер.

Как я уже сказал в комментарии, меня беспокоит, что выбранное вами решение не будет работать должным образом при вставке или обновлении нескольких записей. Триггеры всегда должны быть написаны, чтобы учесть это, так как вы не можете предсказать, произойдут ли они когда-нибудь и когда они произойдут (и в конечном итоге они случаются практически с каждой таблицей).

1 голос
/ 03 сентября 2010
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
0 голосов
/ 18 февраля 2009

Для триггеров в целом вам необходимо использовать курсор для обработки вставок или обновлений нескольких строк. Например:

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, являются большой болью, и я вообще их избегаю.

0 голосов
/ 11 ноября 2008

Использование LIKE даст вам возможность определить, как должна выглядеть остальная часть строки, но если правило начинается с «NoHist_», это не имеет значения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...