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

Откуда:
Сообщений: 44
Столкнулся недавно у клиента с такой ситуацией. Имеется триггер на таблицу персонс

ALTER TRIGGER [dbo].[PERSONS_TRG]
ON [kadr].[dbo].[persons]
AFTER INSERT, UPDATE
AS
BEGIN
      -- DECLARING VARIABLES
      DECLARE @C_ID int;
      DECLARE @ESENED_GUID varchar(255);
      DECLARE @INSCOUNT int;
      DECLARE @DELCOUNT int;
      
      -- SETTING VARIABLES
      SET @SECRETARE = (SELECT top 1 staff_list_type FROM drstaff_list WHERE per_id = 2)
      SELECT TOP 1 
            @C_ID= isnull(per_id,0)     
      FROM inserted;
            
      SET @INSCOUNT = (SELECT top 1 COUNT(*) FROM inserted);
      SET @DELCOUNT = (SELECT top 1 COUNT(*) FROM deleted);

--do something
End


Также имеется триггер на другую таблицу обновляющую данные в первой по некоторому условию


ALTER TRIGGER [dbo].[per_btrip_up_in]
ON [dbo].[per_btrip] AFTER UPDATE,Insert
AS
BEGIN
SET NOCOUNT ON;
Update persons Set status_id='6' where per_id=(select per_id from inserted) 
and  CONVERT(VARCHAR(10), getdate(), 126)>=(select per_btrip_start_date from inserted) and CONVERT(VARCHAR(10), getdate(), 126)<=(select per_btrip_end_date from inserted)
END


При этом обратите внимание условие на выполнение триггера добавлено как условие where. При этом когда срабатывает триггер в таб per_btrip_up_in, то в триггер таб persons количество @INSCOUNT и @DELCOUNT равно 0, а значение праймари ключа естественно не определено, т.е. типа отсуствует и inserted и deleted.

Если же изменить тело второго триггера как подобает на проверку условия типа


if CONVERT(VARCHAR(10), getdate(), 126)>=(select per_btrip_start_date from inserted) and CONVERT(VARCHAR(10), getdate(), 126)<=(select per_btrip_end_date from inserted)
Update persons Set status_id='6' where per_id=(select per_id from inserted) 


то все проходит нормально.
Может кто либо объяснить такое поведение триггера?
6 янв 14, 22:12    [15382526]     Ответить | Цитировать Сообщить модератору
 Re: Странное поведение триггера  [new]
alexeyvg
Member

Откуда: Moscow
Сообщений: 31994
Vugar_Miri
то все проходит нормально.
А что означает "все проходит нормально"?

Условие в IF при этом что, истинно, а в первом случае ложно? Сомнительно, что бы интерпретация условий отличалась от того, в IF эти условия или в WHERE.

Или нормально вы имели в виду, что если условие в WHERE не выполняется, то триггер на persons не должен сработать? Это не так, триггер срабатывает независимо от того, обновилось что нибуть, или нет.
6 янв 14, 22:24    [15382573]     Ответить | Цитировать Сообщить модератору
 Re: Странное поведение триггера  [new]
iap
Member

Откуда: Москва
Сообщений: 47145
Как подобает, говорите?!
Да это просто тихий ужас!
Просто нет слов.

С чего Вы взяли, что вставляться/изменяться будет только одна запись?
Или Вы этот факт проверяете как-то? Не вижу. Поднимите мне веки!
per_id=(select per_id from inserted)
уже для двух записей породит ошибку.
Сравнение с датами вообще не поддаётся пониманию.
Что, в таблице дата хранится в виде строки 126-го формата?! Очень мило!
Не подскажете, когда
SELECT COUNT(*) FROM inserted
вернёт больше одной строки?
Никогда? Зачем же тогда TOP 1? Чтобы запутать?

Я для себя уже давно понял: видишь, как тебе показывают триггер
с объявлениями скалярных переменных, приготовься увидеть говнокод!
Если, конечно, этот триггер не писал я сам!
6 янв 14, 22:30    [15382601]     Ответить | Цитировать Сообщить модератору
 Re: Странное поведение триггера  [new]
Vugar_Miri
Member

Откуда:
Сообщений: 44
И в первом и во втором случае триггер срабатывал при соблюдение условия, только в первом случае в триггере таблицы персонс не возможно было получить ключ в силу отсутсвия записей inserted и deleted (странность именно в этом - не понятно что обновляется в таблице персонс), а вот втором случае "все нормально", т.е. обновляемая запись идентифицируется по inserted, т.е.
 (SELECT TOP 1 @C_ID= isnull(per_id,0)  FROM inserted) <>0
6 янв 14, 22:33    [15382609]     Ответить | Цитировать Сообщить модератору
 Re: Странное поведение триггера  [new]
iap
Member

Откуда: Москва
Сообщений: 47145
Vugar_Miri,

я смотрю, Вы упорствуете. Анализируете первую попавшийся per_id,
делаете на этом основании какие-то выводы... Странно.
6 янв 14, 22:39    [15382626]     Ответить | Цитировать Сообщить модератору
 Re: Странное поведение триггера  [new]
Vugar_Miri
Member

Откуда:
Сообщений: 44
Уважаемый iap, и что полезного я должен почерпнуть из вашего поста? Конечно я тоже мог бы освистать этот код в силу того, что он не мной написан. Я пытался сохранять листинг этого триггера по возможности близким к оригиналу. Мне как профессионалу интерсно было глубокое понимание ситуации. Что же касается ваших сомнений или не понимания кода, то если только, вам это интерсно постараюсь еще раз объяснить, не зависимо от того какое количество записей будет обновляться (SELECT TOP 1 @C_ID= isnull(per_id,0) FROM inserted) должен вернуть по крайней мере одну запись, чего не происходит в первом случае, о чем свидетельствует SET @INSCOUNT = (SELECT top 1 COUNT(*) FROM inserted), котрое равно 0. При этом обратите внимание, что сам триггер сработал! Надеюсь внес немного ясности, если не сумел сделать этого с первого раза.
6 янв 14, 22:41    [15382632]     Ответить | Цитировать Сообщить модератору
 Re: Странное поведение триггера  [new]
iap
Member

Откуда: Москва
Сообщений: 47145
Vugar_Miri,

а почему триггер не должен сработать, если была команда INSERT или команда UPDATE?
Выполните
UPDATE [dbo].[persons] SET status_id=6 WHERE 2*2=5;
и убедитесь, что триггер сработал, а inserted и deleted пусты.
Ваше сравнение дат, преобразованных в строку в WHERE UPDATEа
как раз и сыграло с Вами такую шутку.

Писать TOP 1 без ORDER BY имеет смысл очень редко.
Потому что isnull(per_id,0) не равно 0 в этой записи, но может быть равно 0 во второй.
И что это для Вас будет означать? В следующий раз будет выбрана вторая запись для проверки,
но ситуация реально не изменится. И что же Вы выясняете своим сравнением?
6 янв 14, 22:52    [15382693]     Ответить | Цитировать Сообщить модератору
 Re: Странное поведение триггера  [new]
invm
Member

Откуда: Москва
Сообщений: 9845
Vugar_Miri
(SELECT TOP 1 @C_ID= isnull(per_id,0) FROM inserted) должен вернуть по крайней мере одну запись
С чего вдруг?
Триггеры срабатывают на операцию. Если инструкция не обработала ни одной записи, то триггер все равно будет вызван, а таблицы inserted/deleted будут пустыми.
6 янв 14, 22:59    [15382723]     Ответить | Цитировать Сообщить модератору
 Re: Странное поведение триггера  [new]
Vugar_Miri
Member

Откуда:
Сообщений: 44
К сожалениию уже не имею возможности проверить самому. поэтому буду продолжать теоретическое обоснование. Если можно тут поподробнее, значит ли вами вышесказанное, что даже при
Update persons Set status_id='6' where per_id=(select per_id from inserted) and false

сработает триггер в таблице Персонс? Да и еще, при осмотре кода я не мог делать изменения кода, в силу отсутсвия на тот момент разработчика ихней системы. Я только мог дебагить имеющийся код, при этом тестовый скрипт вставлял одну единственную запись, по этой причине я и не рассматривал вариант обновления многих записей.
6 янв 14, 23:08    [15382774]     Ответить | Цитировать Сообщить модератору
 Re: Странное поведение триггера  [new]
sdet
Member

Откуда:
Сообщений: 463
Vugar_Miri
К сожалениию уже не имею возможности проверить самому. поэтому буду продолжать теоретическое обоснование. Если можно тут поподробнее, значит ли вами вышесказанное, что даже при
Update persons Set status_id='6' where per_id=(select per_id from inserted) and false

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

Может вам отдохнуть и попробовать еще раз прочитать, что вам написали?
6 янв 14, 23:14    [15382798]     Ответить | Цитировать Сообщить модератору
 Re: Странное поведение триггера  [new]
alexeyvg
Member

Откуда: Moscow
Сообщений: 31994
Vugar_Miri
Если можно тут поподробнее, значит ли вами вышесказанное, что даже при
Update persons Set status_id='6' where per_id=(select per_id from inserted) and false

сработает триггер в таблице Персонс?
Естественно, я же про это написал.

Триггер - это хранимая процедура, которая вызывается после выполнения команды изменения данных, независимо от того, было что то реально изменено или нет (а если было, то неважно сколько записей, эта хранимая процедура вызовется один раз).
6 янв 14, 23:20    [15382829]     Ответить | Цитировать Сообщить модератору
 Re: Странное поведение триггера  [new]
alexeyvg
Member

Откуда: Moscow
Сообщений: 31994
Vugar_Miri
Конечно я тоже мог бы освистать этот код в силу того, что он не мной написан. Я пытался сохранять листинг этого триггера по возможности близким к оригиналу. Мне как профессионалу интерсно было глубокое понимание ситуации.
Ну я надеюсь, что, как профессионал, вы его освистали доведением до начальства, какой кривой и глючный код находится в эксплуатации. Триггер ужасен, это так.
Vugar_Miri
постараюсь еще раз объяснить, не зависимо от того какое количество записей будет обновляться (SELECT TOP 1 @C_ID= isnull(per_id,0) FROM inserted) должен вернуть по крайней мере одну запись, чего не происходит в первом случае, о чем свидетельствует SET @INSCOUNT = (SELECT top 1 COUNT(*) FROM inserted), котрое равно 0. При этом обратите внимание, что сам триггер сработал! Надеюсь внес немного ясности, если не сумел сделать этого с первого раза.
Интересное объяснение от профессионала :-)

Я то вначале думал, что из за каких то тонкостей оптимизатора сиквел по разному интерпретирует условия в IF и WHERE, а оно вон что... :-)
6 янв 14, 23:25    [15382851]     Ответить | Цитировать Сообщить модератору
 Re: Странное поведение триггера  [new]
Vugar_Miri
Member

Откуда:
Сообщений: 44
Я несмотря на свой 15 летний опыт программирования, из них 7 лет на SQL абсолютно не стыжусь того, чего не знаю. Более того считаю важным для себя в первую очередь находить бреши в своих знаниях. Поэтому делюсь с сообществом своими знаниями и незнаниями. В любом случае спасибо всем, сегодня я почерпнул для себя кое что новое. Благодарю всех! :)
6 янв 14, 23:44    [15382910]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить