作为一个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调用包装成了开始/结束事务
请注意,此脚本会被调用一次,以将架构的某些旧部分迁移到新部件。它不是性能密集型的,只需要一次“
答案 0 :(得分:2)
你的桌子上有触发器吗?如果更新触发器更新其自己的表,它将再次触发自身,这将再次更新表,等等。
您是否在代码中的任何位置使用视图或功能?视图可以调用其他视图或函数,这些视图或函数调用其他视图/函数。
答案 1 :(得分:1)
光标在这里,虽然让我的皮肤爬行,但可能不是你看到的错误的原因。无法看到嵌套存储过程正在做什么,这只是一个有根据的猜测,但这可能是问题所在。
每当递归SQL操作基本上陷入无限循环时,就会发生错误。我遇到它的两种方式是写一个写得不好的递归CTE(基本上是一个无限联合自身的表),或者在这种情况下,更可能是一个存储过程调用一个调用存储过程的存储过程。等等。例如(我还没有测试过)如果p_selectOrCreateRenewalOptions调用了p_MigrateRenewalOptions,你可能会看到类似的错误。