SQL触发器在删除过程中仅返回一条记录

SQL触发器在删除过程中仅返回一条记录,sql,sql-server,triggers,Sql,Sql Server,Triggers,下面是我为SQL数据库中的表创建的触发器(我们正在运行SQL Server 2008)。我们将批量进行更新、插入和删除,因此我们创建了这个触发器和一个“存储”表(TransactionLog)来捕获所有活动。到目前为止,这个触发器对于插入和更新非常有效。所有记录都以所有适当的值结束在“存储”表中 但是,当我们试图删除多个记录时,就会出现问题。此触发器捕获并发送到“存储”表的唯一记录是删除的最后一条记录。其他人都迷路了 CREATE TRIGGER [dbo].[trg_Agent_ALL] O

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

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

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),而表字符串列(连接值的目标)的数据类型为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和controlId字段强制转换为nvarchar,我能够越过我以前的错误消息。但是,现在我收到一条不同的错误消息,如下所示:

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

select@sNumber=sNumber,…
语法将为每一行覆盖一次变量,因此您只会得到最后一行的值

然后你还要在…中插入一个
。。。值(…)
,只能插入一行

您应该尝试将其改写为以下形式:

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

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

您只需要执行一个
insert
-您知道
inserted
deleted
表可以有多行吗?是的,但是它会捕获插入表中的所有记录。我是否需要更改从已删除表中提取的语法?我怀疑触发器每次执行仅获得一次插入。每次执行删除似乎都有多行。注释结束时太长,因此给出了答案:)
SymetraNumber
可能是一个int,因此SQL Server在看到
+
时会尝试进行数字相加。将其替换为
CAST(SymetraNumber,varchar)
(在另一个CAST中)。@tableString是需要从许多被“删除”的值中连接起来的。我应该在调用INSERT语句之前设置它,还是可能在它内部设置它?如果它只是来自同一行的多个值,然后我将在insert语句中构建它:
insert TransactionLog选择a+b+c作为表字符串
只要其中没有任何空值,这似乎就可以工作。有没有办法在SELECT语句中执行其中一个空值检查?
ISNULL(a,,)
如果
a
为空,将返回一个空字符串,因此您可以执行类似
ISNULL(a,,)+ISNULL(b,,)+ISNULL(c,,)
gotcha,谢谢(编辑上面的代码以显示这些更改)
insert into TransactionLog ( ... )
select sNumber, ... from deleted