Триггер для запуска только в том случае, если условие выполнено в 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 в этом сценарии? Я знаю, что я принял ответ, но я хотел бы узнать его собственное образование.
Ответы
Ответ 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, являются большой болью, и я вообще не использую их.