如何获取递归 CTE 中生成的最后一条记录?

发布于 2024-07-04 17:31:38 字数 1112 浏览 7 评论 0原文

在下面的代码中,我使用 SQL Server 2005 中的递归 CTE(公用表表达式)来尝试查找基本层次结构的顶级父级。 此层次结构的规则是每个 CustID 都有一个 ParentID,如果 CustID 没有父级,则 ParentID = CustID 并且它是最高级别。

DECLARE @LookupID int

--Our test value
SET @LookupID = 1

WITH cteLevelOne (ParentID, CustID) AS
(
        SELECT   a.ParentID, a.CustID
        FROM     tblCustomer AS a
        WHERE    a.CustID = @LookupID
    UNION ALL
        SELECT   a.ParentID, a.CustID
        FROM     tblCustomer AS a
        INNER JOIN cteLevelOne AS c ON a.CustID = c.ParentID
        WHERE c.CustID <> a.CustomerID
)

因此,如果 tblCustomer 看起来像这样:

ParentID    CustID
5            5
1            8
5            4
4            1

我从上面的代码得到的结果是:

ParentID    CustID
4            1
5            4
5            5

我想要的只是该结果的最后一行:

ParentID    CustID
5            5

如何返回 CTE 中生成的最后一条记录(这将是最高级别的 CustID)?

另请注意,此表中有多个不相关的 CustID 层次结构,因此我不能只执行 SELECT * FROM tblCustomer WHERE ParentID = CustID。 我无法按 ParentID 或 CustID 进行排序,因为 ID 号与其在层次结构中的位置无关。

In the code below I am using a recursive CTE(Common Table Expression) in SQL Server 2005 to try and find the top level parent of a basic hierarchical structure. The rule of this hierarchy is that every CustID has a ParentID and if the CustID has no parent then the ParentID = CustID and it is the highest level.

DECLARE @LookupID int

--Our test value
SET @LookupID = 1

WITH cteLevelOne (ParentID, CustID) AS
(
        SELECT   a.ParentID, a.CustID
        FROM     tblCustomer AS a
        WHERE    a.CustID = @LookupID
    UNION ALL
        SELECT   a.ParentID, a.CustID
        FROM     tblCustomer AS a
        INNER JOIN cteLevelOne AS c ON a.CustID = c.ParentID
        WHERE c.CustID <> a.CustomerID
)

So if tblCustomer looks like this:

ParentID    CustID
5            5
1            8
5            4
4            1

The result I get from the code above is:

ParentID    CustID
4            1
5            4
5            5

What I want is just the last row of that result:

ParentID    CustID
5            5

How do I just return the last record generated in the CTE (which would be highest level CustID)?

Also note that there are multiple unrelated CustID hierarchies in this table so I can't just do a SELECT * FROM tblCustomer WHERE ParentID = CustID. I can't order by ParentID or CustID because the ID number is not related to where it is in the hierarchy.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

夜未央樱花落 2024-07-11 17:31:38

首先,如果任何父子相同,则 cte 将不会完成。 由于它是递归 CTE,因此必须终止。 如果 Parent 和 cust id 相同,循环将不会结束。

消息 530,第 16 级,状态 1,第 15 行
声明终止。 在语句完成之前,最大递归次数 100 已用完。

First the cte will not be finished if any of the parent child are same. As it is a recursive CTE it has to be terminated. Having Parent and cust id same , the loop will not end.

Msg 530, Level 16, State 1, Line 15
The statement terminated. The maximum recursion 100 has been exhausted before statement completion.

只是我以为 2024-07-11 17:31:38

如果您只想获得最高的递归深度,您不能这样做吗?然后,当您实际查询 CTE 时,只需查找具有 max(Depth) 的行? 像这样:

DECLARE @LookupID int

--Our test value
SET @LookupID = 1;

WITH cteLevelOne (ParentID, CustID, Depth) AS
(
        SELECT   a.ParentID, a.CustID, 1
        FROM     tblCustomer AS a
        WHERE    a.CustID = @LookupID
    UNION ALL
        SELECT   a.ParentID, a.CustID, c.Depth + 1
        FROM     tblCustomer AS a
        INNER JOIN cteLevelOne AS c ON a.CustID = c.ParentID 
        WHERE c.CustID <> a.CustID
)
select * from CTELevelone where Depth = (select max(Depth) from CTELevelone)

或者,适应特雷弗的建议,这可以与相同的 CTE 一起使用:

select top 1 * from CTELevelone order by Depth desc

我认为 CustomerID 不一定是您所描述的情况下想要订购的内容,但我对这个问题也不是很清楚。

If you just want want the highest recursion depth couldn't you do something like this?Then, when you actually query the CTE just look for the row with max(Depth)? Like so:

DECLARE @LookupID int

--Our test value
SET @LookupID = 1;

WITH cteLevelOne (ParentID, CustID, Depth) AS
(
        SELECT   a.ParentID, a.CustID, 1
        FROM     tblCustomer AS a
        WHERE    a.CustID = @LookupID
    UNION ALL
        SELECT   a.ParentID, a.CustID, c.Depth + 1
        FROM     tblCustomer AS a
        INNER JOIN cteLevelOne AS c ON a.CustID = c.ParentID 
        WHERE c.CustID <> a.CustID
)
select * from CTELevelone where Depth = (select max(Depth) from CTELevelone)

or, adapting what trevor suggests, this could be used with the same CTE:

select top 1 * from CTELevelone order by Depth desc

I don't think CustomerID was necessarily what you wanted to order by in the case you described, but I wasn't perfectly clear on the question either.

⒈起吃苦の倖褔 2024-07-11 17:31:38

我不确定我完全理解这个问题,但只是为了 hack & 您可以尝试使用斜杠:

SELECT TOP 1 FROM cteLevelOne ORDER BY CustID DESC

这假设 CustID 也按示例中的顺序排列,而不是类似 GUID 的内容。

I'm not certain I fully understand the problem, but just to hack & slash at it you could try:

SELECT TOP 1 FROM cteLevelOne ORDER BY CustID DESC

That assumes that the CustID is also in order as in the example, and not something like a GUID.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文