Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Отсутствие рекурсии триггеров  [new]
sander1
Member

Откуда: Москва
Сообщений: 366
Добрый день! Имеется следующая проблема.
Из-за того, что не включен рекурсивный вызов триггеров, не работает некоторая логика, которую необходимо реализовать в системе. Хотелось бы узнать ваше мнение по поводу того, как лучше обойти проблему.

Подробнее.
1. Имеется некоторый внутрискладской документ; за документ отвечает таблица, которая называется "НПерем".
Документ имеет несколько состояний, и при изменении пользователем одного состояния на другое (изменение поля в таблице), в триггере "НПерем after Update" отрабатывает некоторый блок, назовем "Блок 1", выполняющий пересчет товарных остатков, соответственно новому состоянию документа. (Всего у данного документа сейчас может быть 3 состояния, и он последовательно переходит из одного в другое).

2. Появилась необходимость реализовать новую логику ("Блок 2"). Логика заключается в том, что при изменении пользователем состояния документа (допустим, из состояния 1 в состояние 2), в некоторых случаях (в зависимости от других параметров документа), необходимо автоматически установить следующее состояние (т.е. состояние 3).

3. Если "Блок 2" просто добавить в триггер "НПерем after Update", то схема не работает:
- Пользователь меняет состояние с 1 на 2-е (update НПерем set Состояние = 2 where ...);
- Запускается триггер "НПерем after Update";
- В триггере выполняется "Блок 1", пересчитывающий товарные остатки;
- Выполняется "Блок 2", изменяющий состояние документа на следующее (update НПерем set Состояние = 3 where ...);
- При изменении состояния на 3-е, необходимо опять пересчитать остатки; т.е. должен снова отработать "Блок 1", но он не отрабатывает, т.к. рекурсивные вызовы триггеров отключены (и включать их не планируется).

Может кто-то решал подобные задачи; какие могут быть варианты решения проблемы?
Спасибо.
20 июл 09, 11:42    [7434875]     Ответить | Цитировать Сообщить модератору
 Re: Отсутствие рекурсии триггеров  [new]
Glory
Member

Откуда:
Сообщений: 104760
Любая рекурсия эмулируется циклом
Учитывая, что вложенность вызовов триггеров и процедур ограничена 32мя уровнями
20 июл 09, 11:50    [7434928]     Ответить | Цитировать Сообщить модератору
 Re: Отсутствие рекурсии триггеров  [new]
iap
Member

Откуда: Москва
Сообщений: 46975
Glory
Любая рекурсия эмулируется циклом
Учитывая, что вложенность вызовов триггеров и процедур ограничена 32мя уровнями
Тогда придётся эмулировать и стек для хранения переменных триггера + код,
сохраняющий значения в стеке и восстанавливающий их оттуда.
20 июл 09, 12:11    [7435077]     Ответить | Цитировать Сообщить модератору
 Re: Отсутствие рекурсии триггеров  [new]
vino
Member

Откуда:
Сообщений: 1191
"деревянный" способ:

- Пользователь меняет состояние с 1 на 2-е (update НПерем set Состояние = 2 where ...);
- Запускается триггер "НПерем after Update";

1) убедиться, что рекурсия не сработает, вставив, например,
IF @@TRANCOUNT > 1 RETURN
но нужно это учитывать в бизнес-логике
2) переменная DECLARE @yet tinyint будет считать количество расчетов "Блок 1", сначала SET @yet = 0
3) WHILE true BEGIN
4) - В триггере выполняется "Блок 1", пересчитывающий товарные остатки;
5) IF @yet > 0 RETURN
6) - Выполняется "Блок 2", изменяющий состояние документа на следующее (update НПерем set Состояние = 3 where ...);
7) SET @yet = 1
8) END -- WHILE
20 июл 09, 12:14    [7435109]     Ответить | Цитировать Сообщить модератору
 Re: Отсутствие рекурсии триггеров  [new]
Гавриленко Сергей Алексеевич
Member

Откуда: Moscow
Сообщений: 36801
vino
1) убедиться, что рекурсия не сработает, вставив, например,
IF @@TRANCOUNT > 1 RETURN
А какое отношение транзакция имеет к рекурсии?
20 июл 09, 12:17    [7435137]     Ответить | Цитировать Сообщить модератору
 Re: Отсутствие рекурсии триггеров  [new]
vino
Member

Откуда:
Сообщений: 1191
sander1, есть нюанс для действий:
- В триггере выполняется "Блок 1", пересчитывающий товарные остатки;
- Выполняется "Блок 2", изменяющий состояние документа на следующее (update НПерем set Состояние = 3 where ...);

Обе операции должны учитывать массовость измененных записей.
Для оптимизации вычислений перед всеми расчетами сформировать табличку с ключами обрабатываемых записей, затем после работы "Блок 2" в этой табличке остаются только те ключи, для которых нужно повторить "Блок 1"
20 июл 09, 12:19    [7435151]     Ответить | Цитировать Сообщить модератору
 Re: Отсутствие рекурсии триггеров  [new]
vino
Member

Откуда:
Сообщений: 1191
Сорри за очепятку! Конечно же:
1) убедиться, что рекурсия не сработает, вставив, например,
IF @@NESTLEVEL> 1 RETURN
но нужно это учитывать в бизнес-логике
20 июл 09, 12:22    [7435172]     Ответить | Цитировать Сообщить модератору
 Re: Отсутствие рекурсии триггеров  [new]
sander1
Member

Откуда: Москва
Сообщений: 366
Сразу почему-то в голову пришел такой вариант, пожалуйста, оцените:
1) добавляется второй триггер на update;
2) "блок 2" переносистя во второй триггер, "блок 1" остается в первом.
В результате:
-отрабатывает первый триггер - пересчитываются остатки;
-отрабатывает второй, обновляет таблицу (set Состояние = 3);
Запустится ли в этом случае первый триггер, если обновление таблицы будет во втором?
20 июл 09, 12:31    [7435214]     Ответить | Цитировать Сообщить модератору
 Re: Отсутствие рекурсии триггеров  [new]
sander1
Member

Откуда: Москва
Сообщений: 366
vino
1) убедиться, что рекурсия не сработает


Насколько я понял, вы предлагаете-таки включить рекурсивность?
20 июл 09, 12:35    [7435228]     Ответить | Цитировать Сообщить модератору
 Re: Отсутствие рекурсии триггеров  [new]
vino
Member

Откуда:
Сообщений: 1191
sander1
vino
1) убедиться, что рекурсия не сработает


Насколько я понял, вы предлагаете-таки включить рекурсивность?
Я предложил сделать все в одном тригере и без рекурсии. Внимательнее посмотрите
20 июл 09, 13:19    [7435467]     Ответить | Цитировать Сообщить модератору
 Re: Отсутствие рекурсии триггеров  [new]
Зайцев Фёдор
Member

Откуда: Лужки
Сообщений: 5308
думаю, стоит включить рекурсию
20 июл 09, 13:47    [7435703]     Ответить | Цитировать Сообщить модератору
 Re: Отсутствие рекурсии триггеров  [new]
vino
Member

Откуда:
Сообщений: 1191
Зайцев Фёдор
sander1
...рекурсивные вызовы триггеров отключены (и включать их не планируется)...
Если остальная логика завязана на нерекурсивности триггеров, то не стОит
20 июл 09, 14:02    [7435838]     Ответить | Цитировать Сообщить модератору
 Re: Отсутствие рекурсии триггеров  [new]
vino
Member

Откуда:
Сообщений: 1191
Есть вариант получше:
Что мешает сразу определить нужное состояние, раз
sander1
при изменении пользователем состояния документа (допустим, из состояния 1 в состояние 2), в некоторых случаях (в зависимости от других параметров документа), необходимо автоматически установить следующее состояние (т.е. состояние 3).
?
Если "Блок 2" выполнится до "Блок 1", то никаких циклов не понадобится:
- Пользователь меняет состояние с 1 на 2-е (update НПерем set Состояние = 2 where ...);
- Запускается триггер "НПерем after Update";
- Выполняется "Блок 2", изменяющий состояние документа на следующее (update НПерем set Состояние = 3 where ...);
- Выполняется "Блок 1", пересчитывающий товарные остатки;
20 июл 09, 14:10    [7435893]     Ответить | Цитировать Сообщить модератору
 Re: Отсутствие рекурсии триггеров  [new]
iap
Member

Откуда: Москва
Сообщений: 46975
vino
Зайцев Фёдор
sander1
...рекурсивные вызовы триггеров отключены (и включать их не планируется)...
Если остальная логика завязана на нерекурсивности триггеров, то не стОит
Ну, это-то можно криво, но обойти...
Ведь запрещается только непосредственная рекурсия (например, не срабатывает триггер AFTER UPDATE при UPDATE этой же таблицы в её же триггере AFTER UPDATE).
Другое дело, что при этом и максимальный уровень вложенности уменьшится.

Но вот я думаю, почему за 12 лет мне, например, ни разу не понадобилась рекурсия в триггерах?
Может, дело в самой постановке задачи и методах её решения?
20 июл 09, 14:11    [7435905]     Ответить | Цитировать Сообщить модератору
 Re: Отсутствие рекурсии триггеров  [new]
sander1
Member

Откуда: Москва
Сообщений: 366
iap
Ведь запрещается только непосредственная рекурсия (например, не срабатывает триггер AFTER UPDATE при UPDATE этой же таблицы в её же триггере AFTER UPDATE).


Не могли бы вы объяснить, как именно обойти?
20 июл 09, 15:59    [7436508]     Ответить | Цитировать Сообщить модератору
 Re: Отсутствие рекурсии триггеров  [new]
sander1
Member

Откуда: Москва
Сообщений: 366
vino
Что мешает сразу определить нужное состояние


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

Так что тут логика немного сложнее...
20 июл 09, 16:02    [7436529]     Ответить | Цитировать Сообщить модератору
 Re: Отсутствие рекурсии триггеров  [new]
vino
Member

Откуда:
Сообщений: 1191
sander1
vino
Что мешает сразу определить нужное состояние


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

Так что тут логика немного сложнее...
отдельная процедура - не повод для еще одного тригера и рекурсий. Как раз, если переход в состояние 3 не требует предварительного (и, кстати, абсолютно промежуточного) пересчета товарных остатков в "Блок 1", то достаточно эти записи сразу перевести в состояние 3, вызвав "Блок 2", а потом вызвать "Блок 1".
Насчет отдельной процедуры - вы используете inserted ?
20 июл 09, 16:51    [7436827]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить