Sql server 递归SQL以获取原始替换行

Sql server 递归SQL以获取原始替换行,sql-server,tsql,recursive-query,Sql Server,Tsql,Recursive Query,我在Microsoft SQL Server 2008中使用T/SQL,并且有一个具有以下结构的用户许可证表: LicenceID (PK, uniqueidentifier, not null) SupersededID (FK, uniqueidentifier, not null) …other licence related columns 当用户升级其许可证密钥时,将使用原始许可证ID填充该密钥。这可能会发生多次,因此始终可以追溯到发放的第一个许可证。许可证密钥也可能永远不会被取代

我在Microsoft SQL Server 2008中使用T/SQL,并且有一个具有以下结构的用户许可证表:

LicenceID (PK, uniqueidentifier, not null)
SupersededID (FK, uniqueidentifier, not null)
…other licence related columns
当用户升级其许可证密钥时,将使用原始许可证ID填充该密钥。这可能会发生多次,因此始终可以追溯到发放的第一个许可证。许可证密钥也可能永远不会被取代

我遇到的困难是,我需要能够查询licenses表中的所有行,并提取每个行的第一个原始许可证密钥

我相信这可以通过使用WITH方法递归调用查询来实现,但我并不完全清楚这个概念。。这就是我到目前为止所做的:

WITH c AS (SELECT SupersededByID, LicenceID, LicenceID AS topParentID FROM Licence where SupersededBy IS NOT NULL UNION ALL SELECT l.SupersededBy, l.LicenceID, c.topparentid FROM Licence AS l INNER JOIN c ON l.id = c.SupersededByID WHERE T.SupersededByID IS NOT NULL) SELECT * FROM c
对于递归,必须从根记录开始,这些根记录是被取代的dbyid=NULL的记录。这些将为您提供当前的许可证,您需要追溯这些许可证

因此,基本的递归查询如下所示:

WITH c AS
(
     SELECT SupersededById,
            LicenceId,
            LicenceId AS BaseId, 
            1 as Level
     FROM   Licence
     WHERE SupersededById IS NULL
     UNION ALL
     SELECT l.SupersededById,
            l.LicenceId,
            c.BaseId, 
            c.Level + 1 as Level
     FROM   Licence AS l
            INNER JOIN c ON l.SupersededById = c.LicenceId
)
SELECT * FROM c
这将为您提供带有两个附加列的所有记录:每次返回到被取代的许可证时,“级别”列都会上升。BaseId是在许可证跟踪上保持不变的常量

因此,使用这组数据,您可以查找每个BaseId具有最大级别的记录,这可以通过一个子选择来完成:

WITH c AS
(
     SELECT SupersededById,
            LicenceId,
            LicenceId AS BaseId,
            1 as Level
     FROM   Licence
     where SupersededById ByIS NULL
     UNION ALL
     SELECT l.SupersededById,
            l.LicenceId,
            c.BaseId,
            c.Level + 1 as Level
     FROM   Licence AS l
            INNER JOIN c ON l.SupersededById = c.LicenceId
)
SELECT c1.LicenceId as OriginalLicence FROM c as c1
WHERE c1.Level = (SELECT MAX(c2.Level) FROM c as c2 WHERE c2.BaseId = c1.BaseId)

顺便说一句:如果你想从源表中获得更多的列,你只需要将它们添加到所有选择中。

你考虑过使用SCD type 2表吗?这将避免递归。感谢您的故障排除。对于我试图在匆忙中提出一个问题来说,就这么多了。仅供参考:每次我在没有MaxRecursion选项的情况下发布递归CTE,OP在处理实际数据时都会进入默认的递归限制。哈博:我原希望100件再授权书能与现实世界中实际发生的情况相吻合,但对阿德斯堡来说:你知道如果不是这样,你必须做些什么:-谢谢@TToni,不过我想我还是遗漏了一些东西。。当我运行查询时,所有内容似乎都达到了1级结果,我知道有些许可证最多有4个。最后一个连接不应该是这个吗?l.Dbyd=c上的内部联接c。LicenceId@Adsborough:是的,你是对的。我写它的方式,第二部分永远不起作用,因为它将l.LicenseID与NULL进行比较,这总是错误的。将在答案中解决它。