1

I am using T/SQL in Microsoft SQL Server 2008 and have a user Licence table which has the following structure:

LicenceID (PK, uniqueidentifier, not null)
SupersededID (FK, uniqueidentifier, not null)
…other licence related columns

When a user upgrades their licence key, the SupersededID is populated with the original LicenceID. This can occur multiple times and there will therefore always be a trace back to the very first licence that was issued. It is also possible for a licence key to never be superseded.

The difficulty I have is that I need to be able to query all of the rows in the Licences table and extract the very first original licence key for each.

I believe this can be achieved by recursively calling a query using the WITH method, something along these lines, but I'm not totally clear on the concept.. this is what I have so far:


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
4

1 回答 1

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)

顺便说一句:如果您想要源表中的其他列,您只需将它们添加到所有 SELECT 中。

于 2013-06-19T15:43:41.420 回答