Триггеры, изменяющие значение в столбце при изменении в другом столбце
Invite pending
Здравствуйте! Я продемонстрирую как создать на MS SQL триггер, который запишет полное наименование документа в столбец с названием p4758 таблицы attr379 на основании данных в столбцах этой же таблицы.
Я создам данный триггер средствами конфигуратора платформы Клиент Коммуникатор и затем подробно опишу, что получилось.
Вот структура таблицы:

Создаем хранимое вычисление:
Теперь перехожу в Management Studio и смотрю, что у меня получилось.
В базе данных создался новый триггер на таблице attr379. Содержимое триггера:
Триггер действует только на добавление записи и редактирование определенных полей.
Разберем построчно:
Эта строка необходима для того, чтобы не было зацикливания, это как метка «Мы здесь были — больше нам сюда не надо»
Если не менялись данные в столбцах, от которых зависит название документа, то ничего делать и не надо.
Если всё же требуется изменить название документа, то создаем временную таблицу.
Наполняем временную таблицу уникальными ID. Можно еще добавить условие и отобрать только те строки, где произошло изменение в столбцах: p4744, p4727, p4726. Это было бы оправдано в случае, если в таблице много столбцов, т.к. во временную таблицу помещаются все изменившиеся строки, но среди них может быть только одна строка из 1000, в которой требуется изменить название документа.
Если в нашей временной таблице есть записи, то запускаем процедуру изменения наименования документа (её конфигуратор тоже создал автоматически, подробно описывать её не буду):
Последняя строка в триггере. Если мы до неё дошли, то значит уже пора удалять временную таблицу.
Подводим итоги. Чтобы создать триггер, который меняет данные в самой таблице при изменении значений в этой же таблице:
- P4744 — вид документа, ссылка на таблицу attr125, нам необходимо взять значение из P560
- P4727 — дата документа
- P4726 — номер документа.
Я создам данный триггер средствами конфигуратора платформы Клиент Коммуникатор и затем подробно опишу, что получилось.
Вот структура таблицы:

Создаем хранимое вычисление:
- Добавила название вида документа
- Добавила текстовые связки " №" и " от "
- Добавила «номер документа» и «дата документа»
- Нажала на кнопку «Ок».
Теперь перехожу в Management Studio и смотрю, что у меня получилось.
В базе данных создался новый триггер на таблице attr379. Содержимое триггера:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[iuAttr379->P4758] ON [dbo].[Attr379]
AFTER INSERT,UPDATE AS
SET NOCOUNT ON
IF OBJECT_ID (N'tempdb..#UPDATE_ATTR_P4758', N'U') IS NOT NULL return
IF NOT (UPDATE(P4758) OR UPDATE(P4744) OR UPDATE(P4726) OR UPDATE(P4727)) return
CREATE TABLE #UPDATE_ATTR_P4758 (ObjID INT)
INSERT #UPDATE_ATTR_P4758
SELECT DISTINCT ObjectID FROM INSERTED
IF @@ROWCOUNT > 0
EXEC dbo.[_SCUpdateAttr379->P4758]
DROP TABLE #UPDATE_ATTR_P4758
Триггер действует только на добавление записи и редактирование определенных полей.
Разберем построчно:
"IF OBJECT_ID (N'tempdb..#UPDATE_ATTR_P4758', N'U') IS NOT NULL return"
Эта строка необходима для того, чтобы не было зацикливания, это как метка «Мы здесь были — больше нам сюда не надо»
"IF NOT (UPDATE(P4758) OR UPDATE(P4744) OR UPDATE(P4726) OR UPDATE(P4727)) return"
Если не менялись данные в столбцах, от которых зависит название документа, то ничего делать и не надо.
"CREATE TABLE #UPDATE_ATTR_P4758 (ObjID INT)"
Если всё же требуется изменить название документа, то создаем временную таблицу.
"INSERT #UPDATE_ATTR_P4758
SELECT DISTINCT ObjectID FROM INSERTED"
Наполняем временную таблицу уникальными ID. Можно еще добавить условие и отобрать только те строки, где произошло изменение в столбцах: p4744, p4727, p4726. Это было бы оправдано в случае, если в таблице много столбцов, т.к. во временную таблицу помещаются все изменившиеся строки, но среди них может быть только одна строка из 1000, в которой требуется изменить название документа.
"IF @@ROWCOUNT > 0
EXEC dbo.[_SCUpdateAttr379->P4758]"
Если в нашей временной таблице есть записи, то запускаем процедуру изменения наименования документа (её конфигуратор тоже создал автоматически, подробно описывать её не буду):
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[_SCUpdateAttr379->P4758] AS
IF OBJECT_ID (N'tempdb..#UPDATE_ATTR_P4758', N'U') IS NULL
begin
RAISERROR(N'Procedure dbo.[_SCUpdateAttr379->P4758] is need the special table #UPDATE_ATTR_P4758 for correct work!',16,1)
return
end
SET NOCOUNT ON
DECLARE @T Table (ObjectID int, P4758 nvarchar(255))
INSERT @T
SELECT
a0.ObjectID,
a1.P560 + ' № ' + a0.P4726 + ' от ' + a0.P4727
FROM [dbo].[Class379] a0 WITH(UPDLOCK,HOLDLOCK)
JOIN #UPDATE_ATTR_P4758 u ON a0.ObjectID = u.ObjID
LEFT JOIN [dbo].[Class125] a1 ON a1.ObjectID=a0.P4744
WHERE a0.ObjectID > 0
UPDATE a
SET
a.P4758 = t.P4758
FROM [dbo].[Attr379] a, @T t
where a.ObjectID = t.ObjectID
"DROP TABLE #UPDATE_ATTR_P4758"
Последняя строка в триггере. Если мы до неё дошли, то значит уже пора удалять временную таблицу.
Подводим итоги. Чтобы создать триггер, который меняет данные в самой таблице при изменении значений в этой же таблице:
- Надо поставить защиту от зацикливания, в данном примере используется временная таблица
- Ограничить список строк, в которых будем проводить изменения, т.к. именно это влияет на производительность выполнения операции.
- Только если в нашем списке оказались строки, в которых требуются изменения, то выполнить действия.