Подтвердить что ты не робот

Триггер для запуска только в том случае, если условие выполнено в SQL Server

Надеюсь, это достаточно простой вопрос для любых людей 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_%'

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

Любая помощь, которую вы могли бы предложить, была бы оценена.


OK - как и предсказывает Cade Roux, это происходит неэффективно при нескольких обновлениях. Мне придется принять новый подход к этому. Есть ли у кого-нибудь другие предложения, пожалуйста?


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

4b9b3361

Ответ 1

Учитывая, что предложение 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

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

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

Символ _ также является подстановочным знаком, 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

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

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

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

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

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

Ответ 5

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

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

Ответ 7

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

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