递归SQL获取原始的被取代的行

时间:2013-06-19 14:19:34

标签: 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

当用户升级其许可证密钥时,SupersededID将填充原始LicenceID。这可能会多次发生,因此将始终追溯到已发布的第一个许可证。许可证密钥也可能永远不会被取代。

我遇到的困难是我需要能够查询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

1 个答案:

答案 0 :(得分:2)

对于递归,您必须从根记录开始,这些记录是SupersededById = 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)

BTW:如果你想要源表中的其他列,你只需要将它们添加到所有SELECT中。