Я использую Sqlserver Express и не могу запустить before updated
триггер. Есть другой способ сделать это?
Как я могу сделать триггер BEFORE UPDATED с сервером sql?
Ответы (9)
MSSQL не поддерживает триггеры BEFORE
. Самое близкое, что у вас есть, это INSTEAD OF
триггеры, но их поведение отличается от поведения BEFORE
триггеров в MySQL.
Подробнее о них можно узнать здесь, а также отметить что INSTEAD OF
триггеры «Указывает, что триггер выполняется вместо триггерного оператора SQL, таким образом переопределяя действия триггерных операторов». Таким образом, действия по обновлению могут не выполняться, если триггер неправильно написан/обработан. Каскадные действия также затронуты.
Вместо этого вы можете использовать другой подход к тому, чего вы пытаетесь достичь.
Это правда, что в MSSQL нет «до триггеров». Однако вы по-прежнему можете отслеживать изменения, внесенные в таблицу, используя таблицы «вставлено» и «удалено» вместе. Когда обновление вызывает срабатывание триггера, «вставленная» таблица сохраняет новые значения, а «удаленная» таблица сохраняет старые значения. Получив эту информацию, вы могли бы относительно легко смоделировать поведение «до запуска».
Не могу быть уверен, что это применимо к SQL Server Express, но вы все равно можете получить доступ к данным «до», даже если ваш триггер происходит ПОСЛЕ обновления. Вам необходимо прочитать данные из таблицы deleted или inserted, которая создается на лету при изменении таблицы. По сути, это то, что говорит @Stamen, но мне все еще нужно было изучить этот (полезный!) ответ.
В таблице deleted хранятся копии затронутых строк во время операторов DELETE и UPDATE. Во время выполнения инструкции DELETE или UPDATE строки удаляются из триггерной таблицы и переносятся в удаляемую таблицу...
Таблица inserted хранит копии затронутых строк во время операторов INSERT и UPDATE. Во время транзакции вставки или обновления новые строки добавляются как во вставленную таблицу, так и в таблицу триггера...
Таким образом, вы можете создать свой триггер для чтения данных из одной из этих таблиц, например.
CREATE TRIGGER <TriggerName> ON <TableName>
AFTER UPDATE
AS
BEGIN
INSERT INTO <HistoryTable> ( <columns...>, DateChanged )
SELECT <columns...>, getdate()
FROM deleted;
END;
Мой пример основан на приведенном здесь:
T-SQL поддерживает только триггеры AFTER и INSTEAD OF, в нем нет триггера BEFORE, как в некоторых других СУБД.
Я полагаю, вы захотите использовать триггер INSTEAD OF.
Все "обычные" триггеры в SQL Server являются триггерами "ПОСЛЕ...". Триггеров "ДО..." нет.
Чтобы сделать что-то перед обновлением, проверьте ВМЕСТО ОБНОВЛЕНИЯ Триггеры.
Чтобы сделать BEFORE UPDATE
в SQL Server, я использую трюк. Делаю ложное обновление записи (UPDATE Table SET Field = Field
), таким образом получаю предыдущее изображение записи.
Помните, что когда вы используете триггер вместо этого, он не зафиксирует вставку, если вы специально не укажете это в триггере. Вместо того, чтобы действительно означает сделать это вместо того, что вы обычно делаете, чтобы не произошло ни одно из обычных действий вставки.
Полный пример:
CREATE TRIGGER [dbo].[trig_020_Original_010_010_Gamechanger]
ON [dbo].[T_Original]
AFTER UPDATE
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE @Old_Gamechanger int;
DECLARE @New_Gamechanger int;
-- Insert statements for trigger here
SELECT @Old_Gamechanger = Gamechanger from DELETED;
SELECT @New_Gamechanger = Gamechanger from INSERTED;
IF @Old_Gamechanger != @New_Gamechanger
BEGIN
INSERT INTO [dbo].T_History(ChangeDate, Reason, Callcenter_ID, Old_Gamechanger, New_Gamechanger)
SELECT GETDATE(), 'Time for a change', Callcenter_ID, @Old_Gamechanger, @New_Gamechanger
FROM deleted
;
END
END
Обновленные или удаленные значения сохраняются в DELETED. мы можем получить его с помощью метода ниже в триггере
Полный пример,
CREATE TRIGGER PRODUCT_UPDATE ON PRODUCTS
FOR UPDATE
AS
BEGIN
DECLARE @PRODUCT_NAME_OLD VARCHAR(100)
DECLARE @PRODUCT_NAME_NEW VARCHAR(100)
SELECT @PRODUCT_NAME_OLD = product_name from DELETED
SELECT @PRODUCT_NAME_NEW = product_name from INSERTED
END