在递归CTE中使用子查询

时间:2019-08-26 14:57:17

标签: sql-server recursion common-table-expression parent

我有一个SQL表,其中包含项目编号和将其构建到的程序集,因此每个项目都有一行,并且对于一个项目来说,要包含多个行通常是多行的。同样,每个程序集也有一条线,它们与THEY进入的程序集配对,并一直持续到我们到达顶部程序集为止(在Assembly字段中为NULL)。该表(ttibom010124)中的数据如下所示:

Assembly (t_mitm)    Item (t_sitm)
TOPASSY1             SUBASSY1
TOPASSY2             SUBASSY2
SUBASSY1             PART1
SUBASSY1             PART2
SUBASSY2             PART3
SUBASSY2             PART4
PART1                SUBPART1
PART2                SUBPART2
PART3                SUBPART3
PART4                SUBPART4

每个项目还具有一组合同约定的下溢特征,定义为单个字符串中逗号分隔的整数,该字符串位于不同的表中。该表(tqmptc018124)如下所示:

Item (t_item)   Characteristics (t_cdf_qcod)
SUBPART4        01,02,03
SUBPART3        04,05,06
SUBPART2        07,08,09
SUBPART1        10,11,12
PART4           13,14,15
PART3           16,17,18
PART2           19,20,21
PART1           22,23,24
SUBASSY2        25,26,27
SUBASSY1        28,29,30
TOPASSY1        NULL
TOPASSY2        NULL

还有另一个表,其中包含有关每个物料的描述性信息(ttcibd001124),尤其是其中使用该物料的整个产品线。该表实际上很大,但是相关的列是:

Item (t_item)   Product Line (t_cpln)    Item Code (t_citg)
SUBPART4        B21500                   RAW
SUBPART3        B21500                   RAW
SUBPART2        B21500                   RAW
SUBPART1        B21500                   RAW
PART1           B21500                   MFG
PART2           B21500                   MFG 
PART3           B21500                   MFG
PART4           B21500                   MFG
SUBASSY2        B21500                   MFG
SUBASSY1        B21500                   MFG
TOPASSY1        B21500                   FNG
TOPASSY2        B21500                   FNG

最后一个表(ttcmcs061101)是一个小表,用于存储产品线代码和人类可读的说明之间的关系。以下是一些示例行:

Product Line (t_cpln)   Description (t_dsca)
B21500                  Fiber Optics
B36710                  Eurofighter
B65100                  CT Scan

我需要创建一个报告,在该报告中,我们将输入那些特征整数之一,然后在该表的字符串中搜索包含该整数的项,然后在每个项旁边显示相关的顶部程序集。我现在正在SSMS中进行测试,因此当前已对输入进行硬编码,但是当我将代码移至Report Builder时将对其进行参数化。

到目前为止,我有一些工作代码块可以单独完成我想要的工作。我可以在单个项目中进行硬编码,为此我可以找到顶级组件。我还有一个小块,它将接受一个特征并输出应用了该特征的所有项目。但是,当我尝试使用“特征SELECT”语句作为查找“顶级程序集”的块中的子查询时,我得到了大量不具有我感兴趣的“特征”的项目和程序集,即使这是其中的一部分。输入。

-- This block is a recursive CTE that finds the top assemblies 
-- by moving from line to line through the Bill of Materials table.
WITH CTE_TopAssy (
    AssyItem
   ,SubItem)
AS (
    SELECT
        BOM.t_mitm
       ,BOM.t_sitm
    FROM ttibom010124 AS BOM
    WHERE BOM.t_sitm IN

        -- This is a subquery that is supposed to output all the Items 
        -- that contain the Characteristic number from the WHERE line.
        (
            SELECT
                ItemsQD.t_item AS SubqueryItem
            FROM tqmptc018124 AS ItemsQD
            WHERE ItemsQD.t_cdf_qcod LIKE '%03%'
        )  -- 03 is the Characteristic we're searching by

        UNION ALL

        SELECT
            BOM.t_mitm
           ,BOM.t_sitm
        FROM ttibom010124 AS BOM
        INNER JOIN CTE_TopAssy
            ON BOM.t_sitm = CTE_TopAssy.AssyItem
)

-- This is the main query that produces the actual output.
-- It contains references to other tables from which other data tied to the Item number are pulled.
SELECT DISTINCT
        LTRIM(RTRIM(CTE_TopAssy.AssyItem)) AS [Top Assembly]
       ,ItemData.t_cpln                    AS [Product Line]
       ,PLDesc.t_dsca                      AS [PL Name]
       ,LTRIM(RTRIM(CTE_TopAssy.SubItem))  AS Item
    FROM CTE_TopAssy
    INNER JOIN ttcibd001124 AS ItemData
        ON CTE_TopAssy.AssyItem = ItemData.t_item
    INNER JOIN ttcmcs061101 AS PLDesc
        ON ItemData.t_cpln = PLDesc.t_cpln
    --FNG is for Finished Goods, and is the characteristic by which we identify Top Assemblies
    WHERE ItemData.t_citg = 'FNG'  
    ORDER BY
        [Product Line]
       ,[Top Assembly]
;

输出采用预期的格式,但是我将返回的结果限制为具有所需特征的那些项目的“顶级装配体”,而不是获得了不相关且没有该特征的所有项目和装配体。输出显示如下:

Top Assembly     Product Line     PL Name               Item
TOPASSY2         B21500           Fiber Optics          SUBASSY2

所有内容都在正确的位置且类型正确,但不会被我们选择的特征过滤掉。在此示例输出中,我们搜索了'%03%',我们具有正确的Top Assembly,但是Item不正确-它应该是SUBPART4。在我的生产环境中,我得到的特征具有错误的特征或什至没有分配特征的物体,并且它们一直跟随着不应该作为输出一部分的顶级装配。

“%03%”搜索的预期结果将是:

Top Assembly     Product Line     PL Name               Item
TOPASSY2         B21500           Fiber Optics          SUBPART4

“%20%”搜索的预期结果将是:

Top Assembly     Product Line     PL Name               Item
TOPASSY1         B21500           Fiber Optics          PART2

没有错误消息。

我确定问题出在输入行数组而不是输入单个值,但我不知道该怎么办。

我用以下新测试数据添加了一个SQL Fiddle:http://sqlfiddle.com/#!18/e77e5/5/0

1 个答案:

答案 0 :(得分:0)

没有数据与示例数据和查询一起返回。 请更新您的问题。

这是我的查询:

IF OBJECT_ID('tempdb..#ttibom010124') IS NOT NULL
    DROP TABLE #ttibom010124

IF OBJECT_ID('tempdb..#tqmptc018124') IS NOT NULL
    DROP TABLE #tqmptc018124

IF OBJECT_ID('tempdb..#ttcibd001124') IS NOT NULL
    DROP TABLE #ttcibd001124

IF OBJECT_ID('tempdb..#ttcmcs061101') IS NOT NULL
    DROP TABLE #ttcmcs061101

IF OBJECT_ID('tempdb..#CTE_TopAssy') IS NOT NULL
    DROP TABLE #CTE_TopAssy


SELECT '6525039002' AS t_mitm, '8D004C0N01' AS t_sitm INTO #ttibom010124 UNION
SELECT '731114300G' AS t_mitm, '7311143000' AS t_sitm UNION
SELECT '731114300G' AS t_mitm, '7311113000' AS t_sitm UNION
SELECT '731114300G' AS t_mitm, '7C09E00PG0' AS t_sitm UNION
SELECT NULL         AS t_mitm, '731114300G' AS t_sitm UNION
SELECT '731114300G' AS t_mitm, '9L35WMP032' AS t_sitm UNION
SELECT '731114400G' AS t_mitm, '7311144000' AS t_sitm UNION
SELECT '731114400G' AS t_mitm, '7311113000' AS t_sitm UNION
SELECT '6525039000' AS t_mitm, '8D004C0N01' AS t_sitm UNION
SELECT '6525039001' AS t_mitm, '8D004C0N01' AS t_sitm UNION
SELECT '6525039003' AS t_mitm, '8D004C0N01' AS t_sitm UNION
SELECT '6525039004' AS t_mitm, '8D004C0N01' AS t_sitm

SELECT '8D004C0N01' AS t_item, '1,4,10,12,19,21,34,44B,49B,59' AS t_cdf_qcod INTO #tqmptc018124 UNION
SELECT '7311144000' AS t_item, '1,4,10,12,19A,21,34,44A,49B,59' AS t_cdf_qcod UNION
SELECT '7C09E00PG0' AS t_item, '1,4,10B,12,19,21,34,44A,49B,59,61' AS t_cdf_qcod UNION
SELECT '7311113000' AS t_item, '1,4,12,32,41,54A' AS t_cdf_qcod 

SELECT '8D004C0N01' AS t_item, 'B21500' AS t_cpln, 'MFG' AS t_citg INTO #ttcibd001124 UNION
SELECT '7311144000' AS t_item, 'B21500' AS t_cpln, 'RAW' AS t_citg UNION
SELECT '7C09E00PG0' AS t_item, 'B36710' AS t_cpln, 'RAW' AS t_citg UNION
SELECT '7311113000' AS t_item, 'B65100' AS t_cpln, 'FNG' AS t_citg 

SELECT 'B21500' AS t_cpln, 'Fiber Optics' AS t_dsca INTO #ttcmcs061101 UNION
SELECT 'B36710' AS t_cpln, 'Eurofighter' AS t_dsca UNION
SELECT 'B65100' AS t_cpln, 'CT Scan' AS t_dsca


;
-- This block is a recursive CTE that finds the top assemblies 
-- by moving from line to line through the Bill of Materials table.
WITH CTE_TopAssy (
    AssyItem
   ,SubItem)
AS (
    SELECT
        BOM.t_mitm
       ,BOM.t_sitm
    FROM #ttibom010124 AS BOM
    WHERE BOM.t_sitm IN

        -- This is a subquery that is supposed to output all the ICNs 
        -- that contain the SQAP number from the WHERE line.
        (
            SELECT
                ItemsQD.t_item AS SubqueryItem
            FROM #tqmptc018124 AS ItemsQD
            WHERE ItemsQD.t_cdf_qcod LIKE '%49B%'
        )  -- 49B is the Characteristic we're searching by

        UNION ALL

        SELECT
            BOM.t_mitm
           ,BOM.t_sitm
        FROM #ttibom010124 AS BOM
        INNER JOIN CTE_TopAssy
            ON BOM.t_sitm = CTE_TopAssy.AssyItem
)
SELECT
        *
    INTO #CTE_TopAssy
    FROM CTE_TopAssy
--AssyItem      SubItem
--6525039000    8D004C0N01
--6525039001    8D004C0N01
--6525039002    8D004C0N01
--6525039003    8D004C0N01
--6525039004    8D004C0N01
--731114300G    7C09E00PG0
--731114400G    7311144000
--NULL          731114300G


-- This is the main query that produces the actual output.
-- It contains references to other tables from which other data tied to the Item number are pulled.
SELECT DISTINCT
        LTRIM(RTRIM(#CTE_TopAssy.AssyItem)) AS [Top Assembly]
       ,ItemData.t_cpln                     AS [Product Line]
       ,PLDesc.t_dsca                       AS [PL Name]
       ,LTRIM(RTRIM(#CTE_TopAssy.SubItem))  AS Item
    FROM #CTE_TopAssy
    INNER JOIN #ttcibd001124 AS ItemData
        ON #CTE_TopAssy.AssyItem = ItemData.t_item
    INNER JOIN #ttcmcs061101 AS PLDesc
        ON ItemData.t_cpln = PLDesc.t_cpln
    --FNG is for Finished Goods, and is the characteristic by which we identify Top Assemblies
    --WHERE ItemData.t_citg = 'FNG'
    ORDER BY
        [Product Line]
       ,[Top Assembly]
;

**编辑开始**

如果我很好理解,您想保留原始的子项目及其顶级装配。 我会建议为此创建一个标量值函数。

CREATE FUNCTION dbo.Get_Top_Assembly (
    @P_SubItem VARCHAR(255))
RETURNS VARCHAR(255)
AS
BEGIN
    DECLARE @Result_AssyItem VARCHAR(255);
    WITH CTE_TopAssy 
    AS (
        SELECT
            BOM.t_mitm AS AssyItem
           ,BOM.t_sitm AS SubItem
        FROM ttibom010124 AS BOM
        WHERE BOM.t_sitm  = @P_SubItem
            UNION ALL

            SELECT
                BOM.t_mitm
               ,BOM.t_sitm
            FROM ttibom010124 AS BOM
            INNER JOIN CTE_TopAssy
                ON BOM.t_sitm = CTE_TopAssy.AssyItem
    )

    SELECT @Result_AssyItem = CTE_TopAssy.AssyItem
    FROM CTE_TopAssy
    -- Return the result of the function
    RETURN @Result_AssyItem

END

GO;

WITH CTE_TopAssy
AS (
    SELECT
        dbo.Get_Top_Assembly(ItemsQD.t_item) AS AssyItem
       ,ItemsQD.t_item                       AS SubItem
    FROM tqmptc018124 AS ItemsQD
    WHERE ItemsQD.t_cdf_qcod LIKE '%03%'
        OR ItemsQD.t_cdf_qcod LIKE '%20%'
)

-- This is the main query that produces the actual output.
-- It contains references to other tables from which other data tied to the Item number are pulled.
SELECT DISTINCT
        LTRIM(RTRIM(CTE_TopAssy.AssyItem)) AS [Top Assembly]
       ,ItemData.t_cpln                    AS [Product Line]
       ,PLDesc.t_dsca                      AS [PL Name]
       ,LTRIM(RTRIM(CTE_TopAssy.SubItem))  AS Item
    FROM CTE_TopAssy
    INNER JOIN ttcibd001124 AS ItemData
        ON CTE_TopAssy.AssyItem = ItemData.t_item
    INNER JOIN ttcmcs061101 AS PLDesc
        ON ItemData.t_cpln = PLDesc.t_cpln
    --FNG is for Finished Goods, and is the characteristic by which we identify Top Assemblies
    WHERE ItemData.t_citg = 'FNG'  
    ORDER BY
        [Product Line]
       ,[Top Assembly]  

结果:

Top Assembly    Product Line    PL Name         Item
TOPASSY1        B21500          Fiber Optics    PART2
TOPASSY2        B21500          Fiber Optics    SUBPART4

** 2nd Edit END BEGIN **

这里是CTE版本,尚未针对性能进行完全优化,但应该易于理解。

WITH CTE_Items
AS (
    SELECT
        ItemsQD.t_item AS SubItem
    FROM tqmptc018124 AS ItemsQD
    WHERE ItemsQD.t_cdf_qcod LIKE '%03%'
        OR ItemsQD.t_cdf_qcod LIKE '%20%'
),

CTE_Assy_Hier
AS (
    SELECT
        BOM.t_mitm AS AssyItem
       ,BOM.t_sitm AS SubItem
       ,i.SubItem  AS Original_SubItem
       ,1          AS Lvl
    FROM ttibom010124 AS BOM
    INNER JOIN CTE_Items i
        ON BOM.t_sitm = i.SubItem
        UNION ALL

        SELECT
            BOM.t_mitm
           ,BOM.t_sitm
           ,CTE_Assy_Hier.Original_SubItem
           ,1 + Lvl AS Lvl
        FROM ttibom010124 AS BOM
        INNER JOIN CTE_Assy_Hier
            ON BOM.t_sitm = CTE_Assy_Hier.AssyItem
),

CTE_MAX_LVL
AS (
    SELECT
        MAX(Lvl) AS maxLvl
       ,Original_SubItem
    FROM CTE_Assy_Hier
    GROUP BY
        Original_SubItem
),
CTE_TopAssy
AS (
    SELECT
        t.AssyItem
       ,t.Original_SubItem AS SubItem
    FROM CTE_Assy_Hier t
    INNER JOIN CTE_MAX_LVL m
        ON t.Original_SubItem = m.Original_SubItem
        AND t.Lvl = m.maxLvl
)
-- This is the main query that produces the actual output.
-- It contains references to other tables from which other data tied to the Item number are pulled.
SELECT DISTINCT
        LTRIM(RTRIM(CTE_TopAssy.AssyItem)) AS [Top Assembly]
       ,ItemData.t_cpln                    AS [Product Line]
       ,PLDesc.t_dsca                      AS [PL Name]
       ,LTRIM(RTRIM(CTE_TopAssy.SubItem))  AS Item
    FROM CTE_TopAssy
    INNER JOIN ttcibd001124 AS ItemData
        ON CTE_TopAssy.AssyItem = ItemData.t_item
    INNER JOIN ttcmcs061101 AS PLDesc
        ON ItemData.t_cpln = PLDesc.t_cpln
    --FNG is for Finished Goods, and is the characteristic by which we identify Top Assemblies
    WHERE ItemData.t_citg = 'FNG'
    ORDER BY
        [Product Line]
       ,[Top Assembly]
;

**编辑END **