#sql #triggers #cursor
#sql #триггеры #курсор
Вопрос:
Я пытаюсь понять основы работы на основе набора. Я прочитал, что операция на основе набора намного лучше по производительности, чем цикл в курсоре. Какие шаги мне предпринять, чтобы преобразовать курсоры в операции набора? Вот пара примеров, с которыми я работаю
CREATE Trigger DataUpdate ON [Data]
FOR UPDATE
AS
SET NOCOUNT ON
BEGIN
declare @Id int
declare cur cursor for select DataId from Deleted
open cur
fetch next from c into @Id
while @@FETCH_STATUS = 0
begin
if
UPDATE(ID) and
UPDATE(Title) or
UPDATE(Description)
BEGIN
update Data
set ModDate = getdate()
where ID = @Id
END
fetch next from c into @Id
end
close cur
deallocate cur
end
И еще один триггер
CREATE TRIGGER DataAudit
ON [Data] FOR UPDATE
AS
SET NOCOUNT ON
IF UPDATE(ModDate)
BEGIN
SET NOCOUNT ON
DECLARE @ParentId INT
DECLARE @ChildId INT
DECLARE @Export BIT
DECLARE cursorInserted CURSOR FOR
select ParentID, ChildID, Export from INSERTED
OPEN cursorInserted
Fetch next from cursorInserted into @ParentId, @ChildId, @Export
WHILE @@FETCH_STATUS = 0
BEGIN
DECLARE @brief BIT
DECLARE cursorBriefcase CURSOR FOR
select ShowExport
from Sites
where SiteID in (select ds.siteid from DataSiteIDs as ds where ChildID = @ChildId)
OPEN cursorBriefcase
-- Perform the first fetch.
FETCH NEXT FROM cursorBriefcase INTO @brief
-- Check @@FETCH_STATUS to see if there are any more rows to fetch.
WHILE @@FETCH_STATUS = 0 and @brief = 0
BEGIN
FETCH NEXT FROM cursorBriefcase INTO @brief
END
CLOSE cursorBriefcase
DEALLOCATE cursorBriefcase
IF @brief = 0 and
@Export = 1 and
((SELECT Distinct ParentID FROM Sites Where ParentID = @ParentId AND (TemplateID = 5 OR TemplateParams = 1) ) > 0) and
((Select Distinct ParentID From SubUserGroupIDs Where ParentID = @ParentId) > 0)
BEGIN
-- Populate the SubAuditItems table with rows on hold
INSERT INTO SubAuditItems (ChildID, ParentID, RecordDate, Type, FromTable)
VALUES (@ChildId, @ParentId, GETDATE(), 'MOD', 'Data')
END
Fetch next from cursorInserted into @ParentId, @ChildId, @Export
END
CLOSE cursorInserted
DEALLOCATE cursorInserted
END
Комментарии:
1. Вики. lessthandot.com/index.php/Cursors_and_How_to_Avoid_Them
Ответ №1:
@Yusuf: Не могли бы вы рассказать нам немного подробнее? чего вы хотите достичь? если вы хотите сохранить записи, удаленные из таблицы, вы можете сделать это следующим образом:
CREATETRIGGER [dbo].[UpdateCustomerHistory]
ON [dbo].[tblCustomers]
AFTER DELETE
AS
---------------------------------------------------
-- Insert the deleted Record in History
---------------------------------------------------
INSERT INTO tblCustomersHistory
(
CustomerId, Name, DateCreated
)
------ Get deleted row
SELECT CustomerId, Name, GETDATE()
FROM DELETED
Комментарии:
1. Спасибо за идею. Ну, в принципе, я хочу пару вещей, в первом случае, когда когда-либо обновляется определенное поле, я хочу автоматически обновлять измененную дату. Это можно делать по одному, но мне нужно обрабатывать для массового обновления, когда несколько элементов будут обновляться одновременно с помощью процедуры. Во втором случае я хочу обновить другую таблицу на основе некоторого условия, которое может исходить из нескольких таблиц.
2. Можете ли вы подробно описать структуру таблиц и некоторые примеры данных?
Ответ №2:
Это должно быть сделано для тела первого триггера:
UPDATE d
SET ModDate = getdate()
FROM inserted i
JOIN data d ON i.id = d.ID
JOIN deleted del ON i.id = del.id
WHERE
(i.Id <> del.id)
OR
(i.title <> del.title)
OR
(i.description <> del.description)
Если я правильно интерпретировал ваш второй пример, тело триггера будет выглядеть примерно так:
INSERT INTO SubAuditItems (ChildID, ParentID, RecordDate, Type, FromTable)
SELECT i.ChildID,i.ParentID, GETDATE(), 'MOD', 'Data'
FROM INSERTED
JOIN DataSiteIDs s ON ds.childid = i.childid
JOIN Sites s ON ds.siteid = s.siteid
WHERE i.Export = 1