递归CTE和SELECT

时间:2017-07-11 09:12:50

标签: sql recursion sql-server-2008-r2 common-table-expression

我写了一个相当简单的递归CTE语句。目的是查找结构并返回顶级项

这是代码

WITH cte_BOM(parent_serial_id, serial_id, serial_batch_no, sort)

AS (SELECT BOM.parent_serial_id, BOM.serial_id, p.serial_batch_no, 1
FROM serial_status AS BOM
INNER JOIN item_serial_nos p ON BOM.parent_serial_id = p.serial_id
WHERE BOM.serial_id = '16320' AND BOM.is_current = 'Y'

UNION ALL

SELECT
BOM1.parent_serial_id, bom1.serial_id, p1.serial_batch_no, cte_BOM.sort + 1
FROM cte_BOM
INNER JOIN serial_status AS BOM1 ON cte_BOM.parent_serial_id = 
BOM1.serial_id
INNER JOIN item_serial_nos p1 ON BOM1.parent_serial_id = p1.serial_id
WHERE BOM1.is_current = 'Y'
)

SELECT TOP 1
cte_BOM.*
FROM
cte_BOM
ORDER BY sort desc

正如您所看到的,我现在只需对serial_id进行硬编码。我现在需要完成的是针对数据子集运行此cte。我现在仍然坚持如何做到这一点。 因此,我将通过另一个select语句生成一个serial_id列表,然后对于每一行使用此serial_id代替当前硬编码的那些并返回第一条记录。重要的是,如果serial_id没有父级仍然应该返回一行

第二个SELECT就是这样:

SELECT serial_id
FROM
item_serial_nos
WHERE
item_serial_nos.item_id = '15683'

任何建议表示赞赏。 (使用SQL 2008 R2)

1 个答案:

答案 0 :(得分:0)

如果我正确理解了您的目标,您只需从cte中删除硬编码serial_id并添加开始serial_id

WITH    cte_BOM(parent_serial_id, serial_id, serial_batch_no, sort, Original_Serial_id)
AS      (
            SELECT      BOM.parent_serial_id
            ,           BOM.serial_id
            ,           p.serial_batch_no
            ,           1
            ,           BOM.serial_id
            FROM        serial_status AS BOM
            INNER JOIN  item_serial_nos p 
                    ON  BOM.parent_serial_id = p.serial_id
            WHERE       BOM.is_current = 'Y'

            UNION ALL

            SELECT      BOM1.parent_serial_id
            ,           bom1.serial_id
            ,           p1.serial_batch_no
            ,           cte_BOM.sort + 1
            ,           cte_BOM.Original_Serial_id
            FROM        cte_BOM
            INNER JOIN  serial_status AS BOM1 
                    ON  cte_BOM.parent_serial_id = BOM1.serial_id
            INNER JOIN  item_serial_nos p1 
                    ON  BOM1.parent_serial_id = p1.serial_id
            WHERE       BOM1.is_current = 'Y'
)

SELECT      cte_BOM.*
FROM        cte_BOM
INNER JOIN  (
                SELECT      cte_BOM.Original_Serial_id
                ,           MAX(sort) sort_max
                FROM        cte_BOM
                WHERE       cte_BOM.Original_Serial_id IN (
                                                                SELECT  serial_id
                                                                FROM    item_serial_nos
                                                                WHERE   item_serial_nos.item_id = '15683'
                                                            )
                GROUP BY    cte_BOM.Original_Serial_id
            ) max_cte
        ON  max_cte.Original_Serial_id = cte_BOM.Original_Serial_id
        AND max_cte.sort_max = cte_BOM.sort

递归CTE仅在从最后select调用时执行,因此仅对在IN查询中选择的那些记录执行。因此,你不应该因此受到性能损失。