2013-04-09 7 views
0

Я проверяю вывод вставленной/удаленной таблицы с помощью следующего триггера, как передать переданную команду UPDATE на сервер после проверки столбцов?SQL Server - вставленная таблица

CREATE TRIGGER Test1_LastUpdate ON Test1 
INSTEAD OF UPDATE 
AS 
    SELECT * FROM Inserted 
    SELECT * FROM Deleted 
GO 

EDIT: Я ищу решение, которое не нужно менять после обновлений схемы.

CREATE TRIGGER Test1_LastUpdate2 ON Test1 
INSTEAD OF UPDATE 
AS 
    --COMMIT UPDATE THAT WAS INTERCEPTED 
END 
+0

Что это значит, что это не соответствует тому, что сделано для стола? Вы прекращаете его переписывать в таблицу, перехватывая «ОБНОВЛЕНИЕ», но вложенные записи должны быть обновлены в таблице, если вы не перехватили их. Похоже, вам нужен триггер 'FOR UPDATE'. –

+0

@ Love2Learn Я понимаю, что перехватываю команду update. Я ищу способ проверить данные, прежде чем они когда-либо сделают это в базе данных. Я хочу проверить вставленные/удаленные таблицы, а затем зафиксировать действие, отправленное на сервер на основе определенных условий. Я отредактирую код, чтобы быть более понятным. – user2255459

ответ

0

Чтобы получить инструкцию UPDATE, используйте SQLprofiler. Вставленная таблица представляет собой снимок того, что вставляется или обновляется (здесь хранятся новые значения). Удаленная таблица - это моментальный снимок того, какие значения в вас изменяются/удаляются. Вы запускаете только исполняемые команды вместо таблицы Test1, и вы можете видеть, что вы обновляете во вставке.

Проверьте это article о триггерах.

0

Ну это один вариант ...

/* 
     Create Table ExampleTable (LastRefreshed DateTime) 
     Go 
     Insert ExampleTable 
     Select GetDate() 
*/ 

Begin Tran 

If  Object_ID('tempdb..#check') Is Not Null Drop Table #check 
Create Table #check (InsertedVal DateTime, DeletedVal DateTime) 

Update ExampleTable 
Set  LastRefreshed = GetDate() 
Output Inserted.LastRefreshed As InsertedVal, Deleted.LastRefreshed As DeletedVal Into #check 

Select * 
From #check 

If  Exists (Select 1 
       From #check 
       Where InsertedVal > DeletedVal) 
Begin 
     Rollback Tran 
End 
Else 
Begin 
     Commit Tran 
End 

Это создает таблицу с DateTime записи. Обновление пытается обновить его до «сейчас», но оно выполняется внутри транзакции и дампы, в которое она вставлена ​​и удалена записи в таблицу temp для работы. После обновления вы можете выполнить любые проверки, которые вы хотите, против данных таблицы, чтобы определить, хотите ли вы совершить или отменить свои изменения. У меня это написано, чтобы всегда откатывать, например, цели.

+0

Нет, у вас не будет бесконечной триггерной петли. Это совершенно неверная информация. Единственными триггерами, которые вы должны беспокоиться о стрельбе из триггера, являются * другие * триггеры, а не тот, который работает. – ErikE

+0

Спасибо @ErikE ... Я слышал это от кого-то еще и никогда не потрудился найти его или подтвердить. Я удалил дезинформацию. Опция по-прежнему действительна, но я действительно хочу избежать увековечения ложной информации. Я посмотрю и воспитаю себя. Благодаря! –

+0

См. [Этот демонстрационный скрипт SQL] (http://sqlfiddle.com/#!6/bc2c6/1). Обратите внимание, что вы можете получить «пинг-понг» между двумя триггерами, но не между ними. Решением для этого является проверка «TRIGGER_NESTLEVEL» и не выполнение какого-либо обновления, если триггер уже работает на правильном уровне вложенности. – ErikE

2

Единственный способ, которым вы «передаете перехваченную команду UPDATE на сервер после проверки столбцов», - это выполнить самостоятельно UPDATE.

Вариант 1 - ROLLBACK

Однако вы сейчас сказали, что вы не хотите, чтобы добавить несколько столбцов в триггере, когда эти столбцы добавляются в таблицу. Таким образом, у вас есть альтернативный вариант просто отменить любые изменения, которые недействительны. Это может выглядеть примерно так:

CREATE TRIGGER TR_Sample_U ON dbo.Sample -- No AFTER trigger needed here! 
AS 
IF EXISTS (--check for disallowed modifications 
    SELECT * 
    FROM 
     Inserted I 
     INNER JOIN Deleted D 
     ON I.SampleID = D.SampleID 
    WHERE 
     I.Something <> D.Something 
     AND I.UpdateDate = D.UpdateDate 
) 
ROLLBACK TRAN; 

Вариант 2 - Выполнение UPDATE в триггер

Однако, если вам нужно больше контроля над тем, что на самом деле влечет за собой обновление, например, необходимости изменить значение, прежде чем оно было совершено , вам нужно будет выполнить обновление самостоятельно. Например:

CREATE TRIGGER TR_Sample_U ON dbo.Sample 
INSTEAD OF UPDATE 
AS 
SET NOCOUNT ON; 
SET XACT_ABORT ON; 

UPDATE S 
SET S.Value = I.Value + '+' 
FROM 
    dbo.Sample S 
    INNER JOIN Inserted I 
     ON S.SampleID = I.SampleID 
; 

Это тривиальный пример, который не делает никаких проверок, но вы получите идею - при выполнении обновления на Sample таблицы, вы увидите, что значение приобретает дополнительный + character - ваше обновление было перехвачено, а значение Inserted (представляющее предлагаемое изменение после обновления) было изменено до его совершения.

See a SQL Fiddle Demo настоящего в действии.

Единственное, что нужно следить за это рекурсии:

  1. Прямая рекурсия

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

  2. Косвенное Рекурсия

    Вы, вероятно, не придется беспокоиться об этом, потому что database-level RECURSIVE TRIGGERS option отключена по умолчанию в SQL Server. Однако, если он включен, вы можете получить тот же запуск триггера, основываясь на новом обновлении.

Они уменьшалось в, по-разному:

  • TRIGGER_NESTLEVEL Проверка внутри триггера, а выход триггера, если уже вложены достаточно глубоко.

  • Чтобы избежать прямой рекурсии, объедините триггеры.

  • В некоторых случаях, когда стратегическое назначение триггера запускается первым/последним, может возникнуть проблема. Вы не можете указать абсолютный порядок, но вы можете выбрать первый и последний.

Обратите внимание, что проблема пинг-понг относится к любому типу триггера, INSTEAD OF или AFTER, который изменяет свою собственную базовую таблицу, или участвует в цепочке обновлений через другой таблицы (которая имеет триггер, который изменяет другая таблица ...), которая в конечном итоге возвращается, чтобы изменить базовую таблицу.

Вариант 2B - предварительный запуск триггера ПОСЛЕ ОБНОВЛЕНИЯ.

Я называю эту опцию 2B, потому что это действительно вариант 2, но с улучшением. Если вы не хотите вручную обновлять триггер каждый раз, когда вы добавляете столбцы в таблицу (это я полностью согласен), вы можете автоматизировать это. Создайте хранимую процедуру, которая может создать соответствующий триггер, который соблюдает все необходимые проверки. Вы можете поместить базовый код для этой проверки в таблицу, затем в SP выберите его в переменные, добавьте скрипт SQL, обновляющий столбцы для окончательного обновления, используя информацию в представлении INFORMATION_SCHEMA.COLUMNS, а затем, наконец, перезапишите триггер. Кроме того, это можно было бы подключить к триггеру DDL, так что он будет на 100% автоматизирован: вы должны добавить или удалить столбец из базовой таблицы, запускать DDL-триггер и переписать триггер DML для вас.

Это звучит очень много, но если вы разработали его для управления данными, его можно было бы обобщить для работы с любой таблицей во всей базе данных, что может иметь большое значение, в зависимости от ваших сценариев использования.

+0

Я ищу, чтобы создать триггер, который мне не придется изменять при добавлении дополнительных столбцов в базу данных, при выполнении внутреннего соединения мне нужно будет сделать каждый столбец явным. Перечисление всех столбцов - это то, чего я пытаюсь избежать. – user2255459

+0

Хорошо, спасибо, что сообщили мне, хотя было бы неплохо, если бы вы могли сказать это в своем вопросе, поэтому я не тратил время на варианты, которые не сработают для вас. – ErikE

+0

жаль, что я перефразировал вопрос с редактированием для кого-то другого, сделав его немного менее явным. – user2255459

Смежные вопросы