2012-09-03 92 views
0

下面是我为SQL数据库中的表创建的触发器(我们正在运行SQL Server 2008)。我们将要进行更新,插入和删除,因此我们创建了这个触发器和一个“存储”表(TransactionLog)来捕获所有的活动。到目前为止,这个触发器对插入和更新非常有用。所有记录都以“所有适当的值”存储在“存储”表中。SQL触发器仅在删除期间返回一条记录

但是,当我们尝试删除超过一条记录时,会出现问题。此触发器捕获并发送到“存储”表的唯一记录是删除的最后一条记录。所有其他人都迷路了。

CREATE TRIGGER [dbo].[trg_Agent_ALL] 
ON [dbo].[Agent] 

FOR INSERT, UPDATE, DELETE 
AS 
BEGIN 

--TransactionLog variables 
DECLARE @tableName char(25) = 'Agent' 
DECLARE @transDate datetime 
DECLARE @lastChangeOperator char(6) 
DECLARE @tableString char(255) 
DECLARE @action char(1) = 'I' 
DECLARE @userId char(25) 

--Trigger table variables 
DECLARE @sNumber char(10) 
DECLARE @controlId char(3) 
DECLARE @entityType char(1) 
DECLARE @firstName nvarchar(50) 
DECLARE @lastName nvarchar(50) 
DECLARE @suffix nvarchar(10) 
DECLARE @corpName nvarchar(100) 


IF EXISTS (SELECT * FROM deleted) 
    BEGIN 
     SET @action = 
      CASE  
       WHEN EXISTS (SELECT * FROM inserted) THEN 'U' 
       ELSE 'D' 
      END 
    END 

IF @action = 'D' 
    BEGIN 
     SELECT @sNumber = sNumber, @lastChangeOperator = LastChangeOperator, @transDate = LastChangeDate, @entityType = EntityType, 
     @firstName = FirstName, @lastName = LastName, @suffix = NameSuffix, @corpName = CorporateName, @controlId = ControlId 
     FROM deleted 

     IF @firstName IS NULL SET @firstName = 'NULL' 
     IF @lastName IS NULL SET @lastName = 'NULL' 
     IF @suffix IS NULL SET @suffix = 'NULL' 
     IF @corpName IS NULL SET @corpName = 'NULL' 
     IF @controlId IS NULL SET @controlId = 'NULL' 

     SET @tableString = 'sNum:' + @sNumber + ' ' + 'EntType:' + @entityType + ' ' + 'Fname:' + @firstName + ' ' + 'Lname:' + @lastname + ' ' + 'suf:' + @suffix + 
      ' ' + 'crpName:' + @corpName + ' ' + 'crlId:' + @controlId 
    END 
ELSE 
    BEGIN 
     SELECT @sNumber = SymetraNumber, @lastChangeOperator = LastChangeOperator, @transDate = LastChangeDate, @entityType = EntityType, 
     @firstName = FirstName, @lastName = LastName, @suffix = NameSuffix, @corpName = CorporateName, @controlId = ControlId 
     FROM inserted 

     IF @firstName IS NULL SET @firstName = 'NULL' 
     IF @lastName IS NULL SET @lastName = 'NULL' 
     IF @suffix IS NULL SET @suffix = 'NULL' 
     IF @corpName IS NULL SET @corpName = 'NULL' 
     IF @controlId IS NULL SET @controlId = 'NULL' 

     SET @tableString = 'sNum:' + @sNumber + ' ' + 'EntType:' + @entityType + ' ' + 'Fname:' + @firstName + ' ' + 'Lname:' + @lastname + ' ' + 'suf:' + @suffix + 
      ' ' + 'crpName:' + @corpName + 'crlId:' + @controlId 
    END 

INSERT INTO TransactionLog (TransactionDate, Operator, TableName, Action, TableString, UserId) 
VALUES (@transDate, 'Op', @tableName, @action, @tableString, @lastChangeOperator) 

END 

根据以下评论,我已经更改了删除部分中的SQL代码。硬编码值似乎正在工作,但我把它们放在那里只是为了显示这些值的主要原因是我需要这些特定列的值。我在上面的代码中使用这些值设置了变量(请参阅DECLARE语句)。但是,这给我以下错误信息:

Conversion failed when converting the varchar value 'P' to data type int. 

此错误来自内部SELECT语句中的EntityType属性。令我困惑的是,此列的数据类型设置为char(1),而TableString列(连接值的目的地)的数据类型为nvarchar(255)。不知道这里的“INT”是哪里来的?

IF @action = 'D' 
    BEGIN 
     INSERT INTO TransactionLog (TransactionDate, Operator, TableName, Action, TableString, UserId) 
     SELECT LastChangeDate, 'Op', 'Agent', 'D', 
     (SELECT CAST(CAST(sNumber as nvarchar) + ' ' + EntityType + ' ' + ISNULL(FirstName, ' ') + ' ' + ISNULL(LastName, ' ') + ' ' + ISNULL(NameSuffix, ' ') + ' ' + 
       ISNULL(CorporateName, ' ') + ' ' + ISNULL(CAST(ControlId as nvarchar), ' ') AS nvarchar) as TableString 
     FROM deleted), LastChangeOperator 
     FROM deleted 
    END 
ELSE 

编辑

通过铸造sNumber和控件ID字段为nvarchar我能搬过去我以前的错误消息。现在,但是我收到一个不同的错误信息贴在下面:

Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression. 

最后编辑

改变子查询,像这样让我多删除的记录返回到审计表,因为我是唯一一个请求记录一次。

IF @action = 'D' 
    BEGIN 
     INSERT INTO TransactionLog (TransactionDate, Operator, TableName, Action, TableString, UserId) 
      SELECT LastChangeDate, 'Op', 'Agent', 'D', 
      CAST('SymNum:' + CAST(SymetraNumber as nvarchar(30)) + ' entType:' + EntityType + ' Fname:' + ISNULL(FirstName, 'NULL') + ' Lname:' + ISNULL(LastName, 'NULL') + 
      ' suff:' + ISNULL(NameSuffix, 'NULL') + ' corpName:' + ISNULL(CorporateName, 'NULL') + ' ctrlId:' + ISNULL(CAST(ControlId as nvarchar(30)), 'NULL') AS nvarchar(30)) as TableString 
      , LastChangeOperator 
     FROM deleted 
    END 
ELSE 
+0

你只做一个'insert' - 你知道'inserted'和'deleted'表可以有多行吗? – Blorgbeard

+0

是的,但它捕获插入表中的所有记录。我是否需要更改我从已删除表中提取的语法? – NealR

+0

我怀疑触发器每次执行只获得一个插入。尽管每次执行时删除似乎都有多行。评论结束了太久,使其成为一个答案:) – Blorgbeard

回答

1

select @sNumber = sNumber, ..语法将覆盖变量一次的每一行,所以你最终只与最后一排的价值观。

然后你也做一个insert into ... values (...),它只能插入一行。

你应该尝试重写它的形式:

insert into TransactionLog (...) 
select sNumber, ... from deleted 

可以使用ISNULL(lastname, 'NULL'),而不是你的if语句。

+0

@tableString是需要连接从一些值拉下来“删除。“我应该在调用INSERT语句之前设置它,还是可能在它之内设置它? – NealR

+0

如果它只是来自同一行的许多值,那么我会在插入语句中构建它:'insert TransactionLog select a + b + c as TableString' – Blorgbeard

+0

这似乎工作,只要我没有任何空值在那里。有没有一种方法来执行SELECT语句中的NULL值检查? – NealR