2010-09-17 55 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); 

更新: 在你最近的言論來看,我想補充一點,你需要嘗試這樣的事情審覈轉移到登錄表:

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

忘了告訴我,我想保存在另一個表 – SlimBoy 2010-09-17 15:37:47

+0

的每一行中所做的所有更改,即「基於集合的聲明」的權利?我尋找解決方案,我發現,但我不明白如何使用它。所以,而不是我的插入使用的權利? – SlimBoy 2010-09-17 15:48:43

+0

@SlimBoy沒錯! – 2010-09-17 15:50:08

1

我看到兩個問題。

  1. 您試圖從(Select * From)查詢寫入varchar變量。如果有人出現並且在你的餐桌上增加了一列,這將會中斷。在select中指定您的列名稱。

  2. 如果您的代碼一次只更新一行,您的觸發器應該可以正常工作。如果更新更多,則INSERTED和DELETED表變量具有多行。因此錯誤。如果您在Oracle工作,您可以簡單地將FOR EACH ROW選項添加到您的觸發器中,並且代碼將光標通過已更改的記錄。

在MSSQL中,如果您真的需要這樣做,您將不得不在DELETED或INSERTED的記錄上打開遊標,並逐一處理行。這可能非常慢。如果我是你,我會嘗試重構這段代碼來使用set操作。

事情是這樣的:

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,登錄,密碼,IDHomePage,IDSkin,IDPerfil,IDCriador,電子郵件,DataCriacao,DataRemocao,Nome是我的表登錄的領域,我保存它們。

INSERT INTO Login_Hs(IDUtilizador,Tabela,方法方法,蔡夫,Campos的,數據) SELECT '1', '登錄', '更新', '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(Convert(varchar(20),d.DataCriacao,105),'NULL')+' - >'+ coalesce(Convert(varchar(20),i.DataCriacao,105), 'NULL')+'};' + 'DataRemocao = {'+ coalesce(Convert(varchar(20),d.DataRemocao,105),'NULL')+' - >'+ coalesce(Convert(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轉換,該轉換可以完成對這些數據進行除草的工作,並檢測對最終用戶良好輸出的更改。 – 2010-09-17 21:32:59