【问题标题】:Recursion in Stored Procedure存储过程中的递归
【发布时间】:2013-11-13 03:05:54
【问题描述】:

大家好,我有一个存储过程,最近被一位正在休假的同事修改,我在递归 SQL 方面的经验非常有限。我目前得到:

最大递归100在语句完成前已经用完

有什么想法吗?

ALTER PROCEDURE [dbo].[SP_BOM_GetRawMBOM]
   @JobNo varchar(20),
   @ImportNo int = NULL
AS
BEGIN
SET NOCOUNT ON

IF @ImportNo IS NULL 
       SELECT @ImportNo = MAX(ImportNo) 
       FROM Import 
       WHERE JobNo = @JobNo AND SourceType = 'MBOM'

--Can't have aggregates in recursive portion of the common table,
--so get what we need to filter and inner join.
SELECT Drawing, MAX(ImportNo) AS ImportNo
INTO #DrawingImportNo 
FROM RawMBOM
WHERE 
    JobNo = @JobNo AND
    ImportNo <= @ImportNo AND
    Drawing NOT LIKE '_3_2_'
GROUP BY Drawing

SET NOCOUNT OFF

;WITH  Mbom AS (
    --Top (Skid) Level
    SELECT
        S.JobNo, 
        S.ImportNo, 
        CAST('»'+RTRIM(S.Drawing) AS varchar(500)) AS KeyField,
        S.Drawing AS Skid,
        S.Drawing,
        S.Drawing AS PartKey,  
        S.PartNo,
        S.Description,
        S.Qty,
        S.PartSize,
        S.PartLength,
        S.Material,
        S.CutLength,
        S.Ported,
        S.Rev,
        S.IsSub
    FROM    RawMbom S
        INNER JOIN #DrawingImportNo D ON D.Drawing = S.Drawing AND D.ImportNo = S.ImportNo 
    WHERE   
        JobNo = @JobNo AND
        RTRIM(PartKey) = '' AND
        NOT EXISTS (SELECT PartKey FROM RawMBOM WHERE JobNo = @JobNo AND ImportNo <= @ImportNo AND PartKey = S.Drawing)
    UNION ALL
    --Recursive parts and subassemblies
    SELECT
        R.JobNo, 
        R.ImportNo, 
        CAST(RTRIM(U.KeyField)+'»'+R.PartKey AS varchar(500)) AS KeyField,
        U.Skid,
        R.Drawing,
        R.PartKey,
        R.PartNo,
        R.Description,
        U.Qty * R.Qty AS Qty,
        R.PartSize,
        R.PartLength,
        R.Material,
        R.CutLength,
        R.Ported,
        R.Rev,
        R.IsSub
    FROM    RawMbom R
        INNER JOIN Mbom AS U ON R.Drawing = U.PartKey
        INNER JOIN #DrawingImportNo D ON D.Drawing = R.Drawing AND D.ImportNo = R.ImportNo
)
SELECT * FROM Mbom 
WHERE
    RTRIM(PartKey) <> '' AND IsSub = 0 AND --Remove assemblies from the mix
    UPPER(LEFT(PartNo,3)) <> 'REF'  AND --Don't pass because it is on ELT or EBOM
    (
        (DATALENGTH(RTRIM(PartSize))>0)  OR
        (DATALENGTH(RTRIM(PartLength))>0) OR
        (DATALENGTH(RTRIM(Material))>0)  OR
        (DATALENGTH(RTRIM(PartNo))>0)  
    ) -- Don't pass on blank parts.

DROP TABLE #DrawingImportNo
END

【问题讨论】:

  • 我试图增加 MAXRECURSION,但它肯定处于某种无限循环中。
  • 请分享有关您的研究和尝试的解决方案的更多详细信息,并告诉我们它们为什么不起作用。
  • Jeroen,增加最大递归率不起作用,因为它陷入了无限循环,所以无论限制如何(我尝试了 0 [infinite] 都无济于事,它们都达到了 [除了无限,我等了几分钟才杀])
  • 我明白了。但无论如何,增加最大递归可能是对抗症状而不是根本原因分析。您肯定已经(或可以)做更多的事情来首先自己找到解决方案?
  • 调试递归查询的一个快速技巧是在初始查询中添加列1 as Depth,在递归部分添加Mbom.Depth + 1,然后通过在@987654325 中添加and Mbom.Depth &lt; 3 来限制递归@ 子句。通常快速查看结果会发现问题所在。

标签: sql sql-server sql-server-2008 recursion recursive-query


【解决方案1】:

通过@HABO,我能够限制查询的深度。这将使我能够更正确地运行和调试它。

对此,HABO 已经通过here 给出了答案。

对于那些懒得点击的人来说,细节是你向主函数添加一个深度或级别列,并在递归部分增加它。 新查询,带有亮点:

BEGIN

SET NOCOUNT ON

IF @ImportNo IS NULL SELECT @ImportNo = MAX(ImportNo) FROM Import WHERE JobNo = @JobNo AND SourceType = 'MBOM'

--Can't have aggregates in recursive portion of the common table,
--so get what we need to filter and inner join.
SELECT Drawing, MAX(ImportNo) AS ImportNo
INTO #DrawingImportNo 
FROM RawMBOM
WHERE 
    JobNo = @JobNo AND
    ImportNo <= @ImportNo AND
    -- Work instruction P.25 x3x2x is a drawing for a prefabricated vessel.
    --Parts do not get processed in the BOM because parts come as
    --part of the vessel.  Example - Site Glasses
    Drawing NOT LIKE '_3_2_'
GROUP BY Drawing

SET NOCOUNT OFF

;WITH  Mbom AS (
    --Top (Skid) Level
    SELECT
        S.JobNo, 
        S.ImportNo, 
        CAST('»'+RTRIM(S.Drawing) AS varchar(500)) AS KeyField,
        S.Drawing AS Skid,
        S.Drawing,
        S.Drawing AS PartKey,  
        S.PartNo,
        S.Description,
        S.Qty,
        S.PartSize,
        S.PartLength,
        S.Material,
        S.CutLength,
        S.Ported,
        S.Rev,
        S.IsSub
        ,1 Depth
    FROM    RawMbom S
        INNER JOIN #DrawingImportNo D ON D.Drawing = S.Drawing AND D.ImportNo = S.ImportNo 
    WHERE   
        JobNo = @JobNo AND
        RTRIM(PartKey) = '' AND
        NOT EXISTS (SELECT PartKey FROM RawMBOM WHERE JobNo = @JobNo AND ImportNo <= @ImportNo AND PartKey = S.Drawing)
    UNION ALL
    --Recursive parts and subassemblies
    SELECT
        R.JobNo, 
        R.ImportNo, 
        CAST(RTRIM(U.KeyField)+'»'+R.PartKey AS varchar(500)) AS KeyField,
        U.Skid,
        R.Drawing,
        R.PartKey,
        R.PartNo,
        R.Description,
        U.Qty * R.Qty AS Qty,
        R.PartSize,
        R.PartLength,
        R.Material,
        R.CutLength,
        R.Ported,
        R.Rev,
        R.IsSub
        ,Depth + 1
    FROM    RawMbom R
        INNER JOIN Mbom AS U ON R.Drawing = U.PartKey
        INNER JOIN #DrawingImportNo D ON D.Drawing = R.Drawing AND D.ImportNo = R.ImportNo
    WHERE Depth < 10
)
SELECT * FROM Mbom 
WHERE
    RTRIM(PartKey) <> '' AND IsSub = 0 AND --Remove assemblies from the mix
    UPPER(LEFT(PartNo,3)) <> 'REF'  AND --Don't pass because it is on ELT or EBOM
    (
        (DATALENGTH(RTRIM(PartSize))>0)  OR
        (DATALENGTH(RTRIM(PartLength))>0) OR
        (DATALENGTH(RTRIM(Material))>0)  OR
        (DATALENGTH(RTRIM(PartNo))>0)  
    ) -- Don't pass on blank parts.

DROP TABLE #DrawingImportNo
END

【讨论】:

    猜你喜欢
    • 2015-08-08
    • 2020-08-07
    • 2010-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-09
    • 1970-01-01
    相关资源
    最近更新 更多