SQL 向上导航和 Return 顶部项目的递归查询

SQL Recursive Query to Navigate Up and Return Top Item

我有一个分层 table 用于存储零件构建。该模式很简单,table 存储一个组件及其父级。 |--Component--|--Parent--|。我正在使用通用 Table 表达式从父部件构建部件列表,这没有问题。

我 运行 遇到的问题是试图从内部组件中确定顶级部分。我调整了 CTE 以从内部零件构建零件列表,但我 运行 遇到了返回 父零件的麻烦。

使用示例可能更容易解释,因此请参阅下文。在示例中,汽车和摩托车是两个顶级部件。确定这一点的唯一方法是在 Parent 列中找到它们,但从不在 Component 列中(我无法控制架构或数据存储方式)。

CREATE TABLE Build
(
    Parent      VARCHAR(20),
    Component   VARCHAR(20)
);

INSERT INTO Build
VALUES
('Car', 'Door'),
('Door', 'Handle'),
('Handle', 'Screw'),
('Motorcycle', 'Frame'),
('Frame', 'Tank'),
('Tank', 'Internals'),
('Internals', 'Screw');

DECLARE @Comp VARCHAR(20) = 'Screw';

WITH UsedPart (Parent, Component, Level)
AS
(
    SELECT
        b.Parent,
        b.Component,
        1
    FROM Build as b
    WHERE b.Component = @Comp
    UNION ALL
    SELECT
        b.Parent,
        b.Component,
        u.Level + 1
    FROM Build as b
    INNER JOIN UsedPart as u
    ON b.Component = u.Parent
)

SELECT
    *
FROM UsedPart

这个returns:

Parent      Component   Level
----------------------------------------
Handle      Screw           1
Internals   Screw           1
Tank        Internals       2
Frame       Tank            3
Motorcycle  Frame           4    <-- Return this
Door        Handle          2
Car         Door            3    <-- Return this

我想出的唯一解决方案是 JOIN 上面的结果集带有一个像 SELECT fparent FROM Build WHERE fparent NOT IN Component 这样的子查询,但这似乎是解决问题的低效方法。

这是解决此问题的一种方法。我确定还有其他人。

DECLARE @Comp VARCHAR(20) = 'Screw';

WITH UsedPart
AS
(
    SELECT
        b.Parent,
        b.Component,
        Level = 1,
        RowNum = ROW_NUMBER() over(order by parent)
    FROM Build as b
    WHERE b.Component = @Comp
    UNION ALL
    SELECT
        b.Parent,
        b.Component,
        u.Level + 1,
        u.RowNum
    FROM Build as b
    INNER JOIN UsedPart as u
    ON b.Component = u.Parent
)
, SortedValues as
(
    SELECT *
        , MyVal = ROW_NUMBER() over(partition by RowNum order by Level desc)
    FROM UsedPart
)

select *
from SortedValues
where MyVal = 1

您只需将 select 更改为:

SELECT u.*
FROM UsedPart u
WHERE NOT EXISTS(SELECT 1 FROM UsedPart p WHERE p.Component=u.Parent)

试试这个:

select Parent
from build
where Parent not in (select Component from build)