首页 > 解决方案 > SQL Server 中的 CTE 查询:结果中存在一行时退出

问题描述

我正在编写一个 SQL Server 程序来优化条形切割。我还没有找到最好的方法。似乎是 CTE 请求,但我被卡住了。

我尝试编写一个存储过程来优化条形切割。对于我的测试,我必须切割 18 块(3 块 1000 毫米、3 块 1500 毫米、3 块 2500 毫米、3 块 3500 毫米、3 块 4500 毫米和 3 块 6000 毫米),我有 3 种尺寸的棒材(5500 毫米、7000 毫米和 8500 毫米)。

之后,我尽可能生成带有任何切口的条形组合。

我尝试了一个while循环和一个临时表,这需要我一个半小时。但我认为我可以通过 CTE 请求做得更好......

现在,我必须生成许多条的每一种组合才能进行 18 次切割。我提出了另一个 CTE 请求,但是当至少一个组合具有所有削减时,我还没有找到停止递归的方法。因此,我的请求找到了超过 1.5 亿个组合,包括 8、9、10、11... 条。它用 18 个小节尝试每个循环。我希望它以 8 条停止(我知道这是我削减所需的最小条数)。而且需要两天多的时间!

我有 2 个临时表,我的条形组合 (#COMBI_BARRE) 具有这种结构: ID_ART:文章标识、颜色、CUT_COMBI:varchar 连接条形组合的剪切 ID:1-2-3-4.. ., NB_CUT 一个整数,用于获取条中的剪切计数,FIRST_CUT 为条中较小的剪切 ID。

我有另一个临时表#DET_BAR,其中包含我的切割细节,有 2 列:ID_COMBI_BAR 条形组合 ID 和 ID_CUT_STR,varchar 中的切割 ID(以避免在 CTE 中转换或转换以获得更好的性能)。

我将结果存储在一个名为 Combi 的表中,其中包含 ID_ART、颜色、连接条形组合 ID (1-2-3-4...) 的 varchar 列 Combi、连接 ID_CUT 的 varchar 列 COMBI_CUT ( 1-2-3-4-5...),NB_BAR 组合中的条数,NB_CUTS:组合中的切割数,MAX_CUTS 我必须为我的文章和颜色进行的切割总数。

由于它每条生成一个循环,因此我尝试添加一个存在子句以在循环数与我的所有切割至少有一个组合时停止递归。我知道如果我可以用 8 条来完成,我一定不能削减 10 条。但我得到一个错误“递归表有多个引用”。

我怎样才能提出我的要求并避免每个循环?

;WITH Combi (ID_ART, COLOR, COMBI, COMBI_CUT, NB_BAR, NB_CUTS, MAX_CUTS)
AS
( SELECT C.ID_ART, 
        C.COLOR,
      '-' + ID_COMBI_BAR_STR + '-',
         '-' + C.CUT_COMBI + '-',
         1,
         C.NB_CUTS,
         ISNULL(MAXI.CUT_NUM,0)
FROM #COMBI_BARRE C with(nolock)
outer apply (select top 1 D.CUT_NUM
             from #DEBITS D
             where D.ID_ART = C.ID_ART
             and D.COLOR= C.COLOR
             order by D.NUM_OCC_DEB desc) MAXI
WHERE C.FIRST_CUT = 1
UNION ALL
SELECT C.ID_ART, 
             C.COLOR, 
             Combi.COMBI  + ID_COMBI_BAR_STR + '-',
             Combi.COMBI_CUT+ C.CUT_COMBI + '-',
             Combi.NB_BAR+ 1,
             Combi.NB_CUTS+ C.NB_CUTS,
             Combi.MAX_CUTS
  FROM #COMBI_BARRE C with(nolock)
  INNER JOIN Combi  on C.ID_ART = Combi.ID_ART
                          and C.COLOR= Combi.COLOR
  where C.FIRST_CUT > Combi.NB_BAR
  and Combi.NB_CUTS+ C.NB_CUTS<= Combi.MAX_CUTS
  and NOT EXISTS(select * from #DET_BAR D with(nolock)
                           where D.ID_COMBI_BAR = C.ID_COMBI_BAR
                           and PATINDEX(D.ID_CUT_STR, Combi.COMBI_CUT) > 0)
 and NOT EXISTS(select top 1 * from Combi Combi2 where Combi2.ID_ART = C.ID_ART and Combi2.COLOR = C.COLOR and Combi2.NB_CUTS = Combi2.MAX_CUTS)
)
select * from Combi 

标签: sqlsql-serverperformancerecursioncommon-table-expression

解决方案


这是装箱问题的一种变体。该搜索词可能会帮助您朝着正确的方向前进。

此外,您可以访问我的Bin Packing页面,该页面为您的问题的更简化版本提供了几种方法。

一个小警告:链接的文章不使用任何(递归)CTE,因此它们不会回答您的特定 CTE 问题。


推荐阅读