我遇到了这个触发器的问题:
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 @Campos=@Campos+'DataRemocao={'+@Old_DataRemocao+' -> ' + @New_DataRemocao +'}; ';
END
IF(EXISTS(SELECT * FROM deleted as del, inserted AS ins WHERE ins.Login<>del.Login))
BEGIN
SELECT @Campos=@Campos+'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 @Campos=@Campos+'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 @Campos=@Campos+'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 :(得分:1)
我看到两个问题。
您正在尝试从(Select * From)查询写入varchar变量。如果有人出现并为您的表添加一列,那将会破坏。在select中指定列名。
如果您的代码一次只更新一行,那么您的触发器应该可以正常工作。如果更新的次数超过,则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;
答案 1 :(得分:0)
嗯,您正试图在潜在的多值查询中捕获单个值。其中一个地方如下:
SELECT @Old_DataRemocao=(SELECT * DataRemocao FROM deleted);
<强>更新强> 根据您最近的评论,我想补充一点,您需要尝试这样的方法来审核登录表的更改:
insert into Login_Hs (columns)
select i.col1, i.col2, ..., i.colN
FROM inserted i
答案 2 :(得分:0)
感谢@Bill,
我这样做并且有效! ID,登录,密码,IDHomePage,IDSkin,IDPerfil,IDCriador,电子邮件,DataCriacao,DataRemocao,Nome是我的表登录的字段,我保存它们。
INSERT INTO Login_Hs(IDUtilizador,Tabela,Metodo,Chave,Campos,Data) SELECT'1','Login','UPDATE','ID ='+ convert(nvarchar,i.ID), 'Login = {'+ Convert(nvarchar,coalesce(d.Login,'NULL'))+' - &gt; '+转换(nvarchar,coalesce(i.Login,'NULL'))+'};' + 'PassWord = {'+ coalesce(d.PassWord,'NULL')+' - &gt; '+ coalesce(i.PassWord,'NULL')+'};' + 'IDHomePage = {'+ Convert(nvarchar,coalesce(d.IDHomePage,'NULL'))+' - &gt; '+ Convert(nvarchar,coalesce(i.IDHomePage,'NULL'))+'};' + 'IDPerfil = {'+ Convert(nvarchar,coalesce(d.IDPerfil,'NULL'))+' - &gt; '+转换(nvarchar,coalesce(i.IDPerfil,'NULL'))+'};' + 'IDCriador = {'+ Convert(nvarchar,coalesce(d.IDCriador,'NULL'))+' - &gt; '+转换(nvarchar,coalesce(i.IDCriador,'NULL'))+'};' + 'Email = {'+ coalesce(d.Email,'NULL')+' - &gt; '+ coalesce(i.Email,'NULL')+'};' + 'DataCriacao = {'+ coalesce(Convert(varchar(20),d.DataCriacao,105),'NULL')+' - &gt; '+ coalesce(Convert(varchar(20),i.DataCriacao,105),'NULL')+'};' + 'DataRemocao = {'+ coalesce(Convert(varchar(20),d.DataRemocao,105),'NULL')+' - &gt; '+ coalesce(Convert(varchar(20),i.DataRemocao,105),'NULL')+'};' + 'Nome = {'+ coalesce(d.Nome,'NULL')+' - &gt; '+ coalesce(i.Nome,'NULL')+'};' , CONVERT(DATETIME,GETDATE(),105) FROM插入i INNER JOIN已删除d ON i.ID = d.ID;
有没有办法只保存不同的那些?