这个递归 CTE 有啥问题,更重要的是,我无法理解啥一般概念?
Posted
技术标签:
【中文标题】这个递归 CTE 有啥问题,更重要的是,我无法理解啥一般概念?【英文标题】:What's wrong with this recursive CTE and more importantly, what general concept am I failing to comprehend?这个递归 CTE 有什么问题,更重要的是,我无法理解什么一般概念? 【发布时间】:2015-09-04 20:05:16 【问题描述】:好的,我正在研究将一组记录转换为分隔列表的问题。这是一个老问题,有几种方法,在很多情况下,我什至不应该在数据库中这样做。但是,在 this 的情况下,我想并且我想使用递归 CTE。
正如我的标题所暗示的那样,我对真正掌握这个概念的困难感到沮丧。过去,我用书籍或互联网帖子中的代码 sn-ps 解决了这个问题,并对其进行了改编并让它们工作。但这总是很难,而且我并没有真正掌握这项技术。我寻找了该技术的一个非常基本的实现,并得到了我用作模型的答案:https://***.com/a/9726839/13748
所以现在,我有这个临时表#POSO,内容如下:
id inspectionLogKey PO SO
--- ---------------- ------------- ---------
1 7 374534-6988 SO37047
2 7 374534-5464 SO34110
3 7 374534-7135 SO37377
4 7 374534-5284 SO33863
5 7 374534-6710 SO36506
6 7 374534-5084 SO33565
根据这些数据,我想生成一个以逗号分隔的 PO 列值列表。我正在尝试用这个(以及一堆令人沮丧的排列)来做到这一点:
WITH POlists(id,POs) AS
(
SELECT p1.id, CONVERT(VARCHAR(MAX),p1.PO) as POs --anchor
FROM #POSO p1
WHERE p1.id = 1
UNION ALL
SELECT p2.id, POs + ',' + p2.PO --recursive
FROM #POSO p2
join POlists ON p2.id + 1 = POlists.id
)
SELECT * FROM POlists;
返回这个:
id POs
--- -----------
1 374534-6988
我知道你们中的一个人将能够在接下来的八分钟内指出代码错误。但我希望有人可以重新定义它正在做什么,这样我就可以真正理解它并将它从这次遭遇中带走,作为未来使用的工具。
也许一旦发生这种情况,我就可以自己回答这个问题了,但是这个查询能否同时处理 PO 和 SO 列,产生两个字段,每个字段都是逗号分隔的列表两个各自的列?
感谢您的宝贵时间!
【问题讨论】:
您说您正在尝试创建以逗号分隔的值列表。与使用递归 cte 相比,您可以更容易地做到这一点。您可以使用 FOR XML 来更轻松、更快速地完成此操作。 sqlservercentral.com/articles/comma+separated+list/71700 @SeanLange - OP 似乎知道不同的方法,但声明“在这种情况下,我想要,并且我想要使用递归 CTE。” 但是递归 cte 是一种效率低下的工具。仅仅因为它可以这样做并不意味着它应该这样做。 没错,我过去也为此使用过 FOR XML PATH。 @SeanLange 当您说“更快”时,您是指更快地编写代码还是更快地执行代码? 写起来肯定更快,根据我的经验,执行起来也更快。当然要看深度。 :) 【参考方案1】:p2.id + 1 = POlists.id
应该是 p2.id - 1 = POlists.id
唯一的错误是代数。
您的第一个 id 是 1。没有行与 p2.id + 1 =1
一样,因为您没有 id 为 0 的行,所以它停在那里。
虽然p2.id = POlists.id + 1
可能会允许在递归部分进行索引查找。
您可能希望在其中设置一个级别列来返回完整的字符串。
WITH POlists(id,POs, Lvl) AS
(
SELECT p1.id, CONVERT(VARCHAR(MAX),p1.PO) as POs, 0 AS Lvl
FROM #POSO p1
WHERE p1.id = 1
UNION ALL
SELECT p2.id, POs + ',' + p2.PO, Lvl + 1
FROM #POSO p2
join POlists ON p2.id = POlists.id + 1
)
SELECT TOP 1 *
FROM POlists
ORDER BY Lvl DESC;
【讨论】:
哇!我只是对此视而不见。那么,关于级别,为什么我不能只取与最高 ID 关联的结果呢?就像SELECT TOP 1 POs FROM POlists ORDER BY id DESC
我的意思是,它现在可以工作,但是还有其他一些我没有想到的情况吗?我认为不是因为我在执行此查询之前在该临时表中创建了 ID。
@clweeks - 好点 - 其余代码依赖于 id
无论如何都是连续的,所以你不妨使用它。从技术上讲,标识列不能保证顺序,但对于临时表,如果您在单个语句中插入,我从未见过差距。以上是关于这个递归 CTE 有啥问题,更重要的是,我无法理解啥一般概念?的主要内容,如果未能解决你的问题,请参考以下文章