2010-09-17 3 views
2

У меня проблема с этим триггером:триггер для обновления нескольких линии

ALTER TRIGGER [dbo].[trg_B_U_Login] 
    ON [dbo].[Login] 
    FOR UPDATE 
AS 
BEGIN 
    IF @@ROWCOUNT = 0 
     RETURN 
    -- SET NOCOUNT ON added to prevent extra result sets from 
    -- interfering with SELECT statements. 
    SET NOCOUNT ON; 

    DECLARE @Campos nvarchar(500); 
    DECLARE @Old_DataRemocao nvarchar(20); 
    DECLARE @New_DataRemocao nvarchar(20); 
    DECLARE @Old_IDCriador nvarchar(10); 
    DECLARE @New_IDCriador nvarchar(10); 
    SELECT @Campos=''; 

    IF(Exists(SELECT * FROM deleted WHERE DataRemocao is NULL)) 
    BEGIN 
     SELECT @Old_DataRemocao='NULL'; 
    END 
    ELSE 
    BEGIN 
     SELECT @Old_DataRemocao=(SELECT * DataRemocao FROM deleted); 
    END 

    IF(Exists(SELECT * FROM inserted WHERE DataRemocao is NULL)) 
    BEGIN 
     SELECT @New_DataRemocao=NULL; 

    END 
    ELSE 
    BEGIN 
     SELECT @New_DataRemocao=(SELECT * DataRemocao FROM inserted); 
    END 

    IF(@Old_DataRemocao<>@New_DataRemocao) 
    BEGIN 
     SELECT @[email protected]+'DataRemocao={'[email protected]_DataRemocao+' -> ' + @New_DataRemocao +'}; '; 
    END 

    IF(EXISTS(SELECT * FROM deleted as del, inserted AS ins WHERE ins.Login<>del.Login)) 
    BEGIN 
     SELECT @[email protected]+'Login={'+ del.Login +' -> '+ ins.Login+'}; ' FROM deleted as del, inserted as ins 
    END 

...... 

    IF(EXISTS(SELECT * FROM deleted as del, inserted AS ins WHERE ins.DataCriacao<>del.DataCriacao)) 
    BEGIN 
     SELECT @[email protected]+'DataCriacao={'+ del.DataCriacao +' -> '+ ins.DataCriacao+'}; ' FROM deleted as del, inserted as ins 
    END 

    IF(EXISTS(SELECT * FROM deleted as del, inserted AS ins WHERE ins.Nome<>del.Nome)) 
    BEGIN 
     SELECT @[email protected]+'Nome={'+ del.Nome +' -> '+ ins.Nome+'}; ' FROM deleted as del, inserted as ins 
    END 

    IF(@Campos<>'') 
    BEGIN 
     INSERT Login_Hs (IDUtilizador, Tabela, Metodo, Chave, Campos, Data) 
      SELECT '1', 'Login', 'UPDATE', 'IDLogin='+Convert(nvarchar,ID), 
       @Campos, CONVERT(DATETIME, GETDATE(), 105) 
      FROM inserted 
    END 
END 

, который сохраняет изменения, сделанные в каждой строке, обновляется и в настоящее время выполняются этим обновлением

UPDATE Login 
SET DataRemocao = CONVERT(datetime,GETDATE(),105) 
WHERE IDPerfil = 25 AND DataRemocao IS NULL; 

который обновляет более чем один ряд

и SQL Server 2008 дает эту ошибку:

Msg 512, Level 16, State 1, Procedure trg_B_U_Login, Line 83 
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression. 
The statement has been terminated. 

Это просто работает, когда я обновляю одну строку. Что я могу сделать, чтобы решить эту проблему?

ответ

0

Ну, вы пытаетесь поймать единственное значение в потенциально многозначном запросе. Одно из таких мест является следующим:

SELECT @Old_DataRemocao=(SELECT * DataRemocao FROM deleted); 

Update: В свете недавних замечаний, я хотел бы добавить, что вам нужно, чтобы попробовать что-то вроде этого, чтобы проверять изменения в регистрационной таблице:

insert into Login_Hs (columns) 
select i.col1, i.col2, ..., i.colN 
FROM inserted i 
+0

Забыл сообщить, что я хочу сохранить все изменения, сделанные в каждой строке в другой таблице – SlimBoy

+0

, что является «основанием на основе набора»? Я ищу решение, и я это нашел, но я не понимал, как его использовать. Так что вместо моей вставки это правильно? – SlimBoy

+0

@SlimBoy это правильно! –

1

Я вижу две проблемы.

  1. Вы пытаетесь написать запрос (Select * From) в переменную varchar. Это сломается, если кто-то появится и добавит столбец к вашему столу. Укажите имя столбца в списке.

  2. Ваш триггер должен работать нормально, если ваш код обновляется только по одной строке за раз. Если вы обновляете более того, переменные таблицы INSERTED и DELETED имеют несколько строк. Таким образом, ошибка. Если вы работаете в Oracle, вы можете просто добавить параметр FOR EACH ROW к вашему триггеру, и код будет курсировать через измененные записи.

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

Что-то вроде этого:

ALTER TRIGGER [dbo].[trg_B_U_Login] 
    ON [dbo].[Login] 
    FOR UPDATE 
AS 
BEGIN 
     INSERT Login_Hs (IDUtilizador, Tabela, Metodo, Chave, Campos, Data) 
      SELECT '1', 'Login', 'UPDATE', 'IDLogin='+Convert(nvarchar,ID), 
      'DataRemocao={'+ coalesce(deleted.campos, 'NULL') + ' -> ' 
       + coalesce(inserted.campos, 'NULL'), 
       CONVERT(DATETIME, GETDATE(), 105) 
      FROM inserted 
       Inner Join deleted on inserted.idcol=deleted.idcol 
END; 
0

Благодаря @Bill,

Я сделал это и работает! ID, Login, PassWord, IDHomePage, IDSkin, IDPerfil, IDCriador, Email, DataCriacao, DataRemocao, Nome - это поля моей таблицы Login и я их сохраняю.

INSERT INTO Login_Hs (IDUtilizador, Tabela, Metodo, Chave, Campos, данные) SELECT '1', 'Логин', 'UPDATE', 'ID =' + преобразовать (NVARCHAR, i.ID), ' Login = {'+ Convert (nvarchar, coalesce (d.Login,' NULL ')) +' -> '+ Convert (nvarchar, coalesce (i.Login,' NULL ')) +'}; ' + 'PassWord = {' + coalesce (d.PassWord, 'NULL') + '->' + coalesce (i.PassWord, 'NULL') + '};' + 'IDHomePage = {' + Convert (nvarchar, coalesce (d.IDHomePage, 'NULL')) + '->' + Convert (nvarchar, coalesce (i.IDHomePage, 'NULL')) + '};' + 'IDPerfil = {' + Convert (nvarchar, coalesce (d.IDPerfil, 'NULL')) + '->' + Convert (nvarchar, coalesce (i.IDPerfil, 'NULL')) + '};' + 'IDCriador = {' + Convert (nvarchar, coalesce (d.IDCriador, 'NULL')) + '->' + Convert (nvarchar, coalesce (i.IDCriador, 'NULL')) + '};' + 'Email = {' + coalesce (d.Email, 'NULL') + '->' + coalesce (i.Email, 'NULL') + '};' + 'DataCriacao = {' + coalesce (Преобразование (varchar (20), d.DataCriacao, 105), 'NULL') + '->' + coalesce (Преобразование (varchar (20), i.DataCriacao, 105), 'NULL') + '};' + 'DataRemocao = {' + coalesce (Преобразование (varchar (20), d.DataRemocao, 105), 'NULL') + '->' + coalesce (Преобразование (varchar (20), i.DataRemocao, 105), 'NULL') + '};' + 'Nome = {' + coalesce (d.Nome, 'NULL') + '->' + coalesce (i.Nome, 'NULL') + '};' , CONVERT (DATETIME, GETDATE(), 105) FROM вставлен i INNER JOIN удален d ON i.ID = d.ID;

Есть ли способ сохранить только те, которые отличаются друг от друга?

+0

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

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