2013-11-22 3 views
1

Запуск в Sql Server 2008 R2, вот мой UPDATE заявление, в котором в настоящее время работает в ПОСЛЕ триггера ВСТАВИТЬ:не может понять, почему это UPDATE заявление работает

UPDATE cases.CASEMASTER 
SET HOLDLETTERSUNTIL = '1/1/9999' 
FROM cases.CASEMASTER C 
     JOIN INSERTED I 
     ON I.CASEID = C.ROWID 
     JOIN events.EVENTLIBRARY L 
     ON L.ROWID = I.DEFINITIONID 
WHERE L.HOLDLETTERS = 1 
     AND C.HOLDLETTERSUNTIL < GETDATE() 

стыков все правильно, и через окно вывода я подтвердил, что условия, где условия оцениваются - в порядке - ЛОЖЬ и ИСТИНА.

И все же по какой-то причине я не могу понять, это утверждение действительно работает и пытается скрыть UPDATE. Поскольку первое условие WHERE является FALSE, я не могу для жизни меня понять, почему это ОБНОВЛЕНИЕ любых строк в случаях. CASEMASTER. Но я знаю, что это так, потому что он отключает триггер на этом столе.

Я пропущу что-то глупо очевидное, глядя на меня в лицо, то есть в обход моего предложения WHERE?

EVENTLIBRARY.HOLDLETTERS - это поле INT, которое может быть -1, 0 или 1, указывая, должно ли какое-то конкретное событие НЕ УДАЛИТЬ, NOTCHANGE или HOLD, когда оно регистрируется на случай.

CASEMASTER.HOLDLETTERUNTIL - поле DATE.

Вставляемая таблица представляет собой EVENTMASTER, который определяет фактические события, зарегистрированные в журнале.

CASEMASTER> EVENTMASTER является 1-N
EVENTMASTER> EVENTLIBRARY является N-1

И теперь я действительно запутался! Он запускает второй триггер. Но в таблице INSERTED второго триггера есть ZERO-строки. Похоже, что Sql Server запускает триггер только потому, что запускается событие запуска, даже если никакие строки не были изменены? Это что-то новое? Я всегда полагал, что если бы не было строк, то триггер AFTER UPDATE не срабатывал.

+0

Действительно ли оно обновляет новые записи значений, условие которых является ложным? –

+0

Вы говорите нам, что нет строки, которая имеет 'events.EVENTLIBRARY.HOLDLETTERS = 1', и все же запрос обновляет некоторые строки в таблице case.CASEMASTER? –

+0

Да, я вручную тестирую его с помощью однострочной вставки жестко закодированных значений. И я специально использую EVENTID, для которого 'HOLDLETTERS = 0', и все же он обновляет case.CASEMASTER. Я совершенно сбит с толку. – eidylon

ответ

5

Не знаете, что EVENTID имеет отношение к чему-либо, учитывая, что я не вижу EVENTID, упомянутого в запросе вообще. Возможно, вы присоединяетесь к большему количеству строк, чем вы думали, потому что вы упустили условие соединения. Я полагаю, что в EVENTLIBRARY есть HOLDLETTERS = 1, даже если он имеет другой EVENTID, чем текущая строка (строки), обновляемая, или другой DEFINITIONID, чем тот, который указан в вашем запросе. Я не знаю, какой должен быть фактический запрос, потому что у меня нет связей между схемой и межсетевыми.

также:

UPDATE C SET HOLDLETTERSUNTIL = '1/1/9999' 
    --^-- this... 
FROM cases.CASEMASTER C --<-- ...should match this 

И, наконец, ваше предположение о том, что триггер срабатывает только когда 1 или более строк на самом деле влияет ложна. Триггер срабатывает для каждого соответствующего оператора, даже если на него не влияют никакие строки.Легкий пример:

USE tempdb; 
GO 

-- simple, empty table: 

CREATE TABLE dbo.flab(i INT); 
GO 

-- simple table that just prints a message: 

CREATE TRIGGER dbo.trFlab 
ON dbo.flab FOR UPDATE 
AS 
BEGIN 
    SET NOCOUNT ON; 

    PRINT 'See?'; 
END 
GO 

-- this query affects zero rows, both because the WHERE condition is false 
-- and also because there are are no rows in the table to begin with! 

UPDATE dbo.flab SET i = 1 WHERE 1 = 2; 

Но результаты показывают, что триггер был уволен:

See? 

(0 row(s) affected) 

Обычно вы проверить, если какие-либо строки на самом деле влияет на триггере по:

IF EXISTS (SELECT 1 FROM inserted) 

и/или

IF EXISTS (SELECT 1 FROM deleted) 

Y наш второй триггер, вероятно, не делает ничего подобного, прежде чем объявить, что он уволил.

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

UPDATE:

Таким образом, кажется, что Sql Server запускает триггер только потому, что инициирующее событие было бежать, даже если ни одна строка не была на самом деле изменилось? Это что-то новое?

Это абсолютно то, что происходит, и это абсолютно не ново. С самого первого примечания в the SQL Server 2005 documentation for CREATE TRIGGER, last updated in July of 2006:

Эти триггеры срабатывают при срабатывании любого действительного события независимо от того, затронуты ли какие-либо строки таблицы. Это по дизайну.

+0

AHHH - хорошо, вы просто ответили на мой обновленный Q. Триггер срабатывает ДАЖЕ ЕСЛИ никаких строк не было затронуто. Это просто кажется ДЕЙСТВИТЕЛЬНО странным для меня, но ... это то, что есть. Теперь мне просто нужно переделать, чтобы справиться с этим. Благодаря!!! – eidylon

+0

Вот почему триггеры UPDATE SQL Server дают вам псевдотаблицы INSERTED/DELETED, чтобы основать вашу процедуру. Пустая таблица INSERTED (нулевые строки) может быть легко реализованным быстрым возвратом, который вам нужно ускорить. В некоторых ситуациях курсор над таблицей INSERTED (возможно, соединенный с другими таблицами) даст лучшую производительность, чем унитарный оператор UPDATE, используемый в вашем текущем подходе. – hardmath

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