【问题标题】:Getting error INSTEAD OF triggers do not support direct recursion?获取错误 INSTEAD OF 触发器不支持直接递归?
【发布时间】:2016-02-07 23:36:43
【问题描述】:

我需要编写一个删除触发器,在删除供应商之前,它将检查其他数据库表上是否存在,如果在其他数据库表上找不到关系,则发送电子邮件给管理员并设置删除标志 = 1,然后不删除记录下次当同一供应商发出删除命令时,它会检查标志并删除该记录。

create TRIGGER [dbo].[trgInsteadOfDelete] ON [dbo].[AP_Vendor] 
INSTEAD OF DELETE
AS
    declare @apdivisionno varchar(2);
    declare @vendorno varchar(7);
    declare @vendorname varchar(30);
    declare @addressline1 varchar(30);
    declare @addressline2 varchar(30);
    declare @addressline3 varchar(30);
    declare @city varchar(20);
    declare @state varchar(2);
    declare @zipcode varchar(10);
    declare @countrycode varchar(3);

    declare @primarycontact varchar(10);
    declare @telephoneno varchar(17);
    declare @telephoneext varchar(5);
    declare @faxno varchar(17);
    declare @emailaddress varchar(250);
    declare @urladdress varchar(50);
    declare @termscode varchar(2);
    declare @reference varchar(15);
    declare @temporyvendor varchar(1);
    declare @creditcardvendor varchar(1);

    declare @holdpayment varchar(1);
    declare @electronicpayment varchar(1);
    declare @standardentryclass varchar(3);
    declare @exemptionnoOnFile varchar(1);
    declare @taxschedule varchar(9);
    declare @taxclass varchar(2);
    declare @accountkey varchar(9);
    declare @SeparateCheck varchar(1);
    declare @Comment varchar(30);
    declare @Sort varchar(10);

    declare @batchfax varchar(1);
    declare @UsePOReceiptOfInvForVendor varchar(1);
    declare @PrimaryPurchaseAddressCode varchar(4);
    declare @VendorType varchar(1);
    declare @Form1099 varchar(1);
    declare @TaxpayerIDSocialSecurityNo varchar(9);
    declare @Box1099 varchar(3);
    declare @MiscBox9 varchar(1);
    declare @LastPurchaseDate datetime;
    declare @LastPaymentDate datetime;

    declare @LastCheckNo varchar(10);
    declare @LastCheckAmt decimal(14, 2);
    declare @RetentionRate decimal(6, 2);
    declare @AverageDaysToPay decimal(3, 0);
    declare @AverageDaysOverDue decimal(3, 0);
    declare @balancedue decimal(15, 2);
    declare @NumberOfInvToUseInCalc decimal(7, 2);
    declare @datecreated datetime;
    declare @timecreated varchar(8);
    declare @UserCreatedKey varchar(10);

    declare @dateupdated datetime;
    declare @timeupdated varchar(8);
    declare @UserUpdatedKey varchar(10);
    declare @UDF_LONG_NAME varchar(60);

    declare @audit_Event varchar(10);
    declare @audit_log varchar(100);
    declare @dbname varchar(50);

    declare @Deletedbname varchar(50);

    declare @rowcount int;
    declare @TableName varchar(50);
    declare @TableFieldName varchar(50);

    declare @dbcounter int;
    declare @tablecounter int;
    declare @cnt INT ;
    DECLARE @selectVendorno varchar(75)

    select @apdivisionno =i.APDivisionNo from deleted i;    
    select @vendorno=i.VendorNo from deleted i; 
    select @vendorname=i.VendorName from deleted i;
    select @addressline1 =i.AddressLine1 from deleted i;    
    select @addressline2=i.AddressLine2 from deleted i; 
    select @addressline3=i.AddressLine3 from deleted i; 
    select @city =i.City from deleted i;    
    select @state=i.state from deleted i;   
    select @zipcode=i.zipcode from deleted i;   
    select @countrycode =i.countrycode from deleted i;  
    select @primarycontact=i.PrimaryContact from deleted i; 
    select @telephoneno=i.TelephoneNo from deleted i;   
    select @telephoneext =i.telephoneext from deleted i;    
    select @faxno=i.faxno from deleted i;   
    select @emailaddress=i.emailaddress from deleted i; 
    select @urladdress =i.urladdress from deleted i;    
    select @termscode=i.termscode from deleted i;   
    select @temporyvendor=i.TemporaryVendor from deleted i; 
    select @creditcardvendor =i.CreditCardVendor from deleted i;    
    select @holdpayment=i.holdpayment from deleted i;   
    select @electronicpayment=i.ElectronicPayment from deleted i;   
    select @standardentryclass=i.StandardEntryClass from deleted i; 
    select @exemptionnoOnFile=i.ExemptionNoOnFile from deleted i;   
    select @taxschedule=i.taxschedule from deleted i;   
    select @taxclass=i.taxclass from deleted i; 
    select @accountkey=i.accountkey from deleted i; 
    select @SeparateCheck=i.SeparateCheck from deleted i;   
    select @Comment=i.Comment from deleted i;   
    select @Sort=i.Sort from deleted i; 
    select @batchfax=i.batchfax from deleted i; 
    select @UsePOReceiptOfInvForVendor=i.UsePOReceiptOfInvForVendor from deleted i; 
    select @PrimaryPurchaseAddressCode=i.PrimaryPurchaseAddressCode from deleted i; 
    select @VendorType=i.VendorType from deleted i; 
    select @Form1099=i.Form1099 from deleted i;
    select @TaxpayerIDSocialSecurityNo=i.TaxpayerIDSocialSecurityNo from deleted i; 
    select @Box1099=i.Box1099 from deleted i;   
    select @MiscBox9=i.MiscBox9 from deleted i;
    select @LastPurchaseDate=i.LastPurchaseDate from deleted i; 
    select @LastPaymentDate=i.LastPaymentDate from deleted i;   
    select @LastCheckNo=i.LastCheckNo from deleted i;
    select @LastCheckAmt=i.LastCheckAmt from deleted i;
    select @RetentionRate=i.RetentionRate from deleted i;
    select @AverageDaysToPay=i.AverageDaysToPay from deleted i;
    select @AverageDaysOverDue=i.AverageDaysOverDue from deleted i;
    select @balancedue=i.balancedue from deleted i;
    select @NumberOfInvToUseInCalc=i.NumberOfInvToUseInCalc from deleted i;
    select @datecreated=i.datecreated from deleted i;
    select @timecreated=i.timecreated from deleted i;
    select @UserCreatedKey=i.UserCreatedKey from deleted i;
    select @dateupdated=i.dateupdated from deleted i;
    select @timeupdated=i.timeupdated from deleted i;
    select @UserUpdatedKey=i.UserUpdatedKey from deleted i;
    select @UDF_LONG_NAME=i.UDF_LONG_NAME from deleted i;
    select @Deletedbname= DB_NAME();

    set  @dbcounter =0;
    set  @tablecounter =0;

    DECLARE @sql NVARCHAR(MAX) 
    DECLARE @deleteSql NVARCHAR(MAX) 

    select @rowcount=count(*) from [Mas_Master].[dbo].[Master_Vendor] where vendorno=@vendorno and deleteflag=1;



    BEGIN
        if(@rowcount<=0) 
        begin

                DECLARE db_cursor CURSOR FOR  
                SELECT [dbname] FROM [Mas_Master].[dbo].[lookup_dbName]

                OPEN db_cursor   
                FETCH NEXT FROM db_cursor INTO @dbname 

                WHILE @@FETCH_STATUS = 0   
                BEGIN   

                           DECLARE Table_cursor CURSOR FOR  
                           SELECT [TableName],[TableFieldName] FROM [Mas_Master].[dbo].[lookupTableName]
                           OPEN Table_cursor   
                           FETCH NEXT FROM Table_cursor INTO @TableName,@TableFieldName 

                           WHILE @@FETCH_STATUS = 0  
                           BEGIN   


                                if(CONCAT(@dbname, '_', @TableName)<>CONCAT(@Deletedbname, '_', 'AP_VENDOR'))  /*Not Check For Same Database */
                                 Begin

                                    set @sql='Select  @cnt=count(*) from ' +@dbname+'.dbo.'+@TableName +' where '+ @TableFieldName +'= ''' + @vendorno + '''';
                                    EXECUTE sp_executesql @sql, N' @cnt int out', @cnt OUTPUT

                                    INSERT INTO Mas_master.dbo.testDelete
                                            VALUES
                                           (
                                           @dbname
                                           ,@TableName
                                           ,@vendorno,@sql,@cnt
                                           )

                                        if(@cnt>0)
                                        Begin
                                            SET @tablecounter = @tablecounter + 1;
                                            break;  
                                        end
                                 End



                                FETCH NEXT FROM Table_cursor INTO @TableName,@TableFieldName 
                           End
                           CLOSE Table_cursor;
                           DEALLOCATE Table_cursor;
                 SET @dbcounter = @dbcounter + 1;
                 FETCH NEXT FROM db_cursor INTO @dbname   
                END 
             CLOSE db_cursor;
            DEALLOCATE db_cursor;
                /* if no match vendor found on other database then mark master table vendor delete*/
                if(@tablecounter=0)
                begin
                       UPDATE [Mas_Master].[dbo].[Master_Vendor]
                         SET [DeleteFlag] = 1
                        where vendorno=@vendorno
                End

        end
        else /* if delete Flag = 1 then delete vendor from current database table and master vendor table */
        Begin
              set @deleteSql= 'DELETE FROM '+@Deletedbname+'.dbo.AP_Vendor WHERE vendorno=@vendorno';
              EXECUTE sp_executesql @deleteSql, N'@vendorno nvarchar(75)', @vendorno = @vendorno
              DELETE FROM Mas_Master.dbo.Master_Vendor WHERE vendorno=@vendorno
        End
    End 

如果使用了 INSTEAD OF 触发器,我收到错误消息 INSTEAD OF 触发器不支持直接递归。

如果我使用删除触发器后,我会收到错误消息

**Msg 3609, Level 16, State 1, Line 1
The transaction ended in the trigger. The batch has been aborted.**


create TRIGGER [dbo].[trgInsteadOfDelete] ON [dbo].[AP_Vendor] 
after DELETE
AS
    declare @apdivisionno varchar(2);
    declare @vendorno varchar(7);
    declare @vendorname varchar(30);
    declare @addressline1 varchar(30);
    declare @addressline2 varchar(30);
    declare @addressline3 varchar(30);
    declare @city varchar(20);
    declare @state varchar(2);
    declare @zipcode varchar(10);
    declare @countrycode varchar(3);

    declare @primarycontact varchar(10);
    declare @telephoneno varchar(17);
    declare @telephoneext varchar(5);
    declare @faxno varchar(17);
    declare @emailaddress varchar(250);
    declare @urladdress varchar(50);
    declare @termscode varchar(2);
    declare @reference varchar(15);
    declare @temporyvendor varchar(1);
    declare @creditcardvendor varchar(1);

    declare @holdpayment varchar(1);
    declare @electronicpayment varchar(1);
    declare @standardentryclass varchar(3);
    declare @exemptionnoOnFile varchar(1);
    declare @taxschedule varchar(9);
    declare @taxclass varchar(2);
    declare @accountkey varchar(9);
    declare @SeparateCheck varchar(1);
    declare @Comment varchar(30);
    declare @Sort varchar(10);

    declare @batchfax varchar(1);
    declare @UsePOReceiptOfInvForVendor varchar(1);
    declare @PrimaryPurchaseAddressCode varchar(4);
    declare @VendorType varchar(1);
    declare @Form1099 varchar(1);
    declare @TaxpayerIDSocialSecurityNo varchar(9);
    declare @Box1099 varchar(3);
    declare @MiscBox9 varchar(1);
    declare @LastPurchaseDate datetime;
    declare @LastPaymentDate datetime;

    declare @LastCheckNo varchar(10);
    declare @LastCheckAmt decimal(14, 2);
    declare @RetentionRate decimal(6, 2);
    declare @AverageDaysToPay decimal(3, 0);
    declare @AverageDaysOverDue decimal(3, 0);
    declare @balancedue decimal(15, 2);
    declare @NumberOfInvToUseInCalc decimal(7, 2);
    declare @datecreated datetime;
    declare @timecreated varchar(8);
    declare @UserCreatedKey varchar(10);

    declare @dateupdated datetime;
    declare @timeupdated varchar(8);
    declare @UserUpdatedKey varchar(10);
    declare @UDF_LONG_NAME varchar(60);

    declare @audit_Event varchar(10);
    declare @audit_log varchar(100);
    declare @dbname varchar(50);

    declare @Deletedbname varchar(50);

    declare @rowcount int;
    declare @TableName varchar(50);
    declare @TableFieldName varchar(50);

    declare @dbcounter int;
    declare @tablecounter int;
    declare @cnt INT ;
    DECLARE @selectVendorno varchar(75)

    select @apdivisionno =i.APDivisionNo from deleted i;    
    select @vendorno=i.VendorNo from deleted i; 
    select @vendorname=i.VendorName from deleted i;
    select @addressline1 =i.AddressLine1 from deleted i;    
    select @addressline2=i.AddressLine2 from deleted i; 
    select @addressline3=i.AddressLine3 from deleted i; 
    select @city =i.City from deleted i;    
    select @state=i.state from deleted i;   
    select @zipcode=i.zipcode from deleted i;   
    select @countrycode =i.countrycode from deleted i;  
    select @primarycontact=i.PrimaryContact from deleted i; 
    select @telephoneno=i.TelephoneNo from deleted i;   
    select @telephoneext =i.telephoneext from deleted i;    
    select @faxno=i.faxno from deleted i;   
    select @emailaddress=i.emailaddress from deleted i; 
    select @urladdress =i.urladdress from deleted i;    
    select @termscode=i.termscode from deleted i;   
    select @temporyvendor=i.TemporaryVendor from deleted i; 
    select @creditcardvendor =i.CreditCardVendor from deleted i;    
    select @holdpayment=i.holdpayment from deleted i;   
    select @electronicpayment=i.ElectronicPayment from deleted i;   
    select @standardentryclass=i.StandardEntryClass from deleted i; 
    select @exemptionnoOnFile=i.ExemptionNoOnFile from deleted i;   
    select @taxschedule=i.taxschedule from deleted i;   
    select @taxclass=i.taxclass from deleted i; 
    select @accountkey=i.accountkey from deleted i; 
    select @SeparateCheck=i.SeparateCheck from deleted i;   
    select @Comment=i.Comment from deleted i;   
    select @Sort=i.Sort from deleted i; 
    select @batchfax=i.batchfax from deleted i; 
    select @UsePOReceiptOfInvForVendor=i.UsePOReceiptOfInvForVendor from deleted i; 
    select @PrimaryPurchaseAddressCode=i.PrimaryPurchaseAddressCode from deleted i; 
    select @VendorType=i.VendorType from deleted i; 
    select @Form1099=i.Form1099 from deleted i;
    select @TaxpayerIDSocialSecurityNo=i.TaxpayerIDSocialSecurityNo from deleted i; 
    select @Box1099=i.Box1099 from deleted i;   
    select @MiscBox9=i.MiscBox9 from deleted i;
    select @LastPurchaseDate=i.LastPurchaseDate from deleted i; 
    select @LastPaymentDate=i.LastPaymentDate from deleted i;   
    select @LastCheckNo=i.LastCheckNo from deleted i;
    select @LastCheckAmt=i.LastCheckAmt from deleted i;
    select @RetentionRate=i.RetentionRate from deleted i;
    select @AverageDaysToPay=i.AverageDaysToPay from deleted i;
    select @AverageDaysOverDue=i.AverageDaysOverDue from deleted i;
    select @balancedue=i.balancedue from deleted i;
    select @NumberOfInvToUseInCalc=i.NumberOfInvToUseInCalc from deleted i;
    select @datecreated=i.datecreated from deleted i;
    select @timecreated=i.timecreated from deleted i;
    select @UserCreatedKey=i.UserCreatedKey from deleted i;
    select @dateupdated=i.dateupdated from deleted i;
    select @timeupdated=i.timeupdated from deleted i;
    select @UserUpdatedKey=i.UserUpdatedKey from deleted i;
    select @UDF_LONG_NAME=i.UDF_LONG_NAME from deleted i;
    select @Deletedbname= DB_NAME();

    set  @dbcounter =0;
    set  @tablecounter =0;

    DECLARE @sql NVARCHAR(MAX) 
    DECLARE @deleteSql NVARCHAR(MAX) 

    select @rowcount=count(*) from [Mas_Master].[dbo].[Master_Vendor] where vendorno=@vendorno and deleteflag=1;



    BEGIN
        if(@rowcount<=0) 
        begin
                Rollback;
                DECLARE db_cursor CURSOR FOR  
                SELECT [dbname] FROM [Mas_Master].[dbo].[lookup_dbName]

                OPEN db_cursor   
                FETCH NEXT FROM db_cursor INTO @dbname 

                WHILE @@FETCH_STATUS = 0   
                BEGIN   

                           DECLARE Table_cursor CURSOR FOR  
                           SELECT [TableName],[TableFieldName] FROM [Mas_Master].[dbo].[lookupTableName]
                           OPEN Table_cursor   
                           FETCH NEXT FROM Table_cursor INTO @TableName,@TableFieldName 

                           WHILE @@FETCH_STATUS = 0  
                           BEGIN   


                                if(CONCAT(@dbname, '_', @TableName)<>CONCAT(@Deletedbname, '_', 'AP_VENDOR'))  /*Not Check For Same Database */
                                 Begin

                                    set @sql='Select  @cnt=count(*) from ' +@dbname+'.dbo.'+@TableName +' where '+ @TableFieldName +'= ''' + @vendorno + '''';
                                    EXECUTE sp_executesql @sql, N' @cnt int out', @cnt OUTPUT

                                    INSERT INTO Mas_master.dbo.testDelete
                                            VALUES
                                           (
                                           @dbname
                                           ,@TableName
                                           ,@vendorno,@sql,@cnt
                                           )

                                        if(@cnt>0)
                                        Begin
                                            SET @tablecounter = @tablecounter + 1;
                                            break;  
                                        end
                                 End



                                FETCH NEXT FROM Table_cursor INTO @TableName,@TableFieldName 
                           End
                           CLOSE Table_cursor;
                           DEALLOCATE Table_cursor;
                 SET @dbcounter = @dbcounter + 1;
                 FETCH NEXT FROM db_cursor INTO @dbname   
                END 
             CLOSE db_cursor;
            DEALLOCATE db_cursor;
                /* if no match vendor found on other database then mark master table vendor delete*/
                if(@tablecounter=0)
                begin
                       UPDATE [Mas_Master].[dbo].[Master_Vendor]
                         SET [DeleteFlag] = 1
                        where vendorno=@vendorno
                End

        end
        else /* if delete Flag = 1 then delete vendor from current database table and master vendor table */
        Begin
              set @deleteSql= 'DELETE FROM '+@Deletedbname+'.dbo.AP_Vendor WHERE vendorno=@vendorno';
              EXECUTE sp_executesql @deleteSql, N'@vendorno nvarchar(75)', @vendorno = @vendorno
              DELETE FROM Mas_Master.dbo.Master_Vendor WHERE vendorno=@vendorno
        End
    End 

请帮帮我?

【问题讨论】:

  • 这是一个糟糕的设计......而且从偶然的观察来看,如果有人试图一次删除多个供应商,这将不起作用。
  • deletedinserted 可以包含 0、1 或 多个 行。你的触发器坏了。

标签: sql-server triggers


【解决方案1】:

您正试图从触发器所基于的同一个表 (AP_Vendor) 中删除,这将导致同一个触发器无休止地(或递归地)触发。也许在从 AP_Vendor 删除的 Maser_Vendor 上触发后创建 AN 会起作用。

【讨论】:

  • 如果我在触发器后使用,我收到错误消息 3609,级别 16,状态 1,第 1 行事务在触发器中结束。该批次已中止
  • 您必须在 Master_Vendor 上创建 AFTER 触发器并使用它来删除关联的 AP_Vendor 记录。由于您已经在 AP_Vendor 触发器中应用了验证逻辑,因此您只需删除关联的 Master_Vendor 记录。
  • 我第一次不想删除记录。当我第二次删除相同的供应商时,它检查删除供应商标志,如果为 1,则删除其他明智的回滚。我在触发器后添加,第一次它是回滚删除的供应商记录并应用验证逻辑并设置删除标志,第二次去删除。
【解决方案2】:

您的触发器最后在同一张表上包含一个 DELETE。通常,INSTEAD OF 触发器中的操作不会再次触发相同的触发器,但由于您使用动态 SQL 执行此操作,这会创建另一个执行上下文,我猜这意味着触发器将再次触发。

您可以检查数据库中嵌套触发器和递归触发器的选项:

EXEC sp_configure 'nested triggers';
EXEC sp_dboption 'YOUR_DATABASE_NAME', 'recursive triggers';

值应为 1 或“ON”。如果没有,您可以激活它们并重试

EXEC sp_configure 'nested triggers', 1;
EXEC sp_dboption 'YOUR_DATABASE_NAME', 'recursive triggers', true;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-04-30
    • 1970-01-01
    • 2014-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-23
    • 2019-03-05
    相关资源
    最近更新 更多