TSQL游标调用存储过程'查看嵌套级别超过'

时间:2014-09-04 18:45:03

标签: sql sql-server tsql

作为一个SQL Newb,我尝试创建一个SQL脚本,使用游标在多行上执行存储过程。我找到了创建游标的代码,存储过程按预期工作。

但是,有时在执行期间我会收到错误

  

超出最大存储过程,函数,触发器或视图嵌套级别(限制32)

这是有问题的SQL脚本。有什么想法我得到这个错误?

CREATE PROCEDURE p_MigrateRenewalOptions
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    DECLARE @OrderId VARCHAR(255) = NULL
    DECLARE @RenewalId INT = 0

    DECLARE @DiscountCode VARCHAR(255) = NULL
    DECLARE @UpgradeCode VARCHAR(255) = NULL
    DECLARE @ProductCode VARCHAR(255) = NULL

    DECLARE rCursor CURSOR FOR  
    SELECT RenewalId FROM t_Renewals WHERE DiscountCode IS NOT NULL AND UpgradeCode IS NOT NULL

    OPEN rCursor
    FETCH NEXT FROM rCursor INTO @RenewalId   

    -- Iterate over t_Renewals with DiscountCode, UpgradeCode
    WHILE @@FETCH_STATUS = 0
    BEGIN

      SELECT @OrderId = OrderId from t_Renewals where RenewalId = @RenewalId
      SELECT @DiscountCode = DiscountCode from t_Renewals where RenewalId = @RenewalId
      SELECT @UpgradeCode = UpgradeCode from t_Renewals where RenewalId = @RenewalId
      SELECT @ProductCode = ProductCode from t_Order Where OrderId = @OrderId

      -- Create renewal options for the t_Renewal entry 
      EXEC p_SelectOrCreateRenewalOptions @OrderId

      -- Migrate the DiscountCode, UpgradeCode from the renewal record 
      UPDATE t_Renewal_Option 
      SET CouponCode = @DiscountCode
      WHERE RenewalId = @RenewalId AND OptionType = 0 AND CouponCode IS NULL

      UPDATE t_Renewal_Option 
      SET CouponCode = @UpgradeCode
      WHERE RenewalId = @RenewalId AND OptionType = 1 AND CouponCode IS NULL

      -- NULL the Renewal record DiscountCode, UpgradeCode 
      UPDATE t_Renewals 
      SET DiscountCode = NULL, UpgradeCode = NULL 
      WHERE RenewalId = @RenewalId

      FETCH NEXT FROM rCursor INTO @RenewalId   
    END

    CLOSE rCursor   
    DEALLOCATE rCursor
END
GO

我注意到的一件事是声明

-- Create renewal options for the t_Renewal entry 
EXEC p_SelectOrCreateRenewalOptions @OrderId

返回一个集合,例如如果在SQL Server Management Studio内部的存储过程之外运行此代码,则会在输出窗口中获得多组结果。这是原因吗?是否可以转储数据,因为我不需要p_SelectOrCreateRenewalOptions

中返回的行

编辑:根据要求,以下是p_SelectOrCreateRenewalOptions的代码

CREATE PROCEDURE p_SelectOrCreateRenewalOptions
(   
    @OrderId VARCHAR(255) = NULL
)
AS
BEGIN

    SET NOCOUNT ON

    DECLARE @ProductCode VARCHAR(255);
    SELECT @ProductCode = ProductCode FROM t_Order WHERE OrderId = @OrderId;

    DECLARE @StaticOptionCount INT;
    SET @StaticOptionCount = dbo.f_QueryRenewalOptionCount(@ProductCode);

    DECLARE @OptionCount INT;
    SELECT @OptionCount = COUNT(*) FROM t_Renewal_Option ro INNER JOIN t_Renewals r ON r.RenewalId = ro.RenewalId WHERE r.OrderId = @OrderId
    IF (@OptionCount != @StaticOptionCount)
    BEGIN
        SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
        BEGIN TRANSACTION   
            SELECT @OptionCount = COUNT(*) FROM t_Renewal_Option ro INNER JOIN t_Renewals r ON r.RenewalId = ro.RenewalId WHERE r.OrderId = @OrderId
            IF (@OptionCount != @StaticOptionCount)
            BEGIN
                DECLARE @RenewalId INT;
                SELECT @RenewalId = RenewalId FROM t_Renewals r WHERE r.OrderId = @OrderId;

                DELETE FROM t_Renewal_Option WHERE RenewalId = @RenewalId;

                INSERT INTO t_Renewal_Option (RenewalId, OptionProductCode, OptionType, LastUpdated) 
                SELECT @RenewalId, sro.OptionProductCode, sro.OptionTypeId, GETDATE()
                FROM t_Static_Renewal_Option sro
                WHERE sro.ProductCode = @ProductCode

            END
        COMMIT TRANSACTION
    END

    SELECT ro.* FROM t_Renewal_Option ro INNER JOIN t_Renewals r ON r.RenewalId = ro.RenewalId WHERE r.OrderId = @OrderId

END
GO

f_QueryRenewalOptionCount只做一个选择:

 -- f_QueryRenewalOptionCount
 SELECT @Count = COUNT(*) FROM t_Static_Renewal_Option o WHERE o.ProductCode = @ProductCode

明智地触发,我认为我们没有任何触发因素。 INSERT上的t_Order表上有一个触发器,但除此之外,没有别的。

更新12-SEP-14:

这个'工作'但我完全不了解这个问题。我将EXEC调用包装成了开始/结束事务

请注意,此脚本会被调用一次,以将架构的某些旧部分迁移到新部件。它不是性能密集型的,只需要一次“

2 个答案:

答案 0 :(得分:2)

你的桌子上有触发器吗?如果更新触发器更新其自己的表,它将再次触发自身,这将再次更新表,等等。

您是否在代码中的任何位置使用视图或功能?视图可以调用其他视图或函数,这些视图或函数调用其他视图/函数。

答案 1 :(得分:1)

光标在这里,虽然让我的皮肤爬行,但可能不是你看到的错误的原因。无法看到嵌套存储过程正在做什么,这只是一个有根据的猜测,但这可能是问题所在。

每当递归SQL操作基本上陷入无限循环时,就会发生错误。我遇到它的两种方式是写一个写得不好的递归CTE(基本上是一个无限联合自身的表),或者在这种情况下,更可能是一个存储过程调用一个调用存储过程的存储过程。等等。例如(我还没有测试过)如果p_selectOrCreateRenewalOptions调用了p_MigrateRenewalOptions,你可能会看到类似的错误。