获取错误INSTEAD OF触发器不支持直接递归?

时间:2014-06-30 11:13:20

标签: sql-server triggers

我要求写一个删除触发器,在删除供应商之前它将检查是否存在于其他数据库表上,如果在其他数据库表中找不到关系,则发送电子邮件给admin并设置delete flag = 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触发器不支持直接递归。

如果我使用After Delete Trigger,我收到错误信息

**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 

请帮帮我?

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:0)

您的触发器在末尾的同一个表中包含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;