请不要在没有阅读的情况下将问题标记为重复。我发布了一个类似的问题,但是,由于解决方案更加复杂,小型,次要的修改,STACKOVERFLOW社区成员要求我重新发布修改后的问题。
假设您有以下架构:
CREATE TABLE Data
(
ID INT,
CXL INT
)
INSERT INTO Data (ID, CXL)
SELECT 1, NULL
UNION
SELECT 2, 1
UNION
SELECT 3, 2
UNION
SELECT 5, 3
UNION
SELECT 6, NULL
UNION
SELECT 7, NULL
UNION
SELECT 8, 7
列CXL是取消特定ID的ID。因此,例如,ID为1的表中的第一行是好的,直到它被ID:2(CXL列)取消。 ID:2一直很好,直到它被ID:3取消。 ID:3是好的,直到它被ID:5取消所以在这个序列中最后一个" GOOD" ID为ID:5。
我想找到" GOOD" ID以及启动EACH链的原始ID。因此,在此示例中,它将是:
Original ID | Latest GOOD ID
1 5
6 6
7 8
如果你想玩这个,这里有一个小提琴: http://sqlfiddle.com/#!6/68ac48/1
答案 0 :(得分:5)
我花了几分钟的时间来挖掘正确的CTE:
WITH ids AS (
SELECT
ID,
ID AS orig FROM Data d1 WHERE CXL IS NULL
UNION ALL
SELECT
d2.ID,
orig
FROM ids i
INNER JOIN Data d2 ON d2.CXL = i.ID
)
SELECT
orig AS [Original Id],
MAX(ID) AS [Latest Good Id]
FROM ids
GROUP BY orig
这假设取消ID总是高于它取消的ID,当然......
基本上,每次递归时,它会再次为该行重新选择原始ID。递归完成后,只需要一个简单的GROUP BY
即可获得原始ID和最新值。
答案 1 :(得分:4)
我认为你可以使用递归CTE来做到这一点:
;WITH CTE AS (
SELECT ID AS Parent, ID, CXL, 0 AS level
FROM Data
WHERE CXL IS NULL
UNION ALL
SELECT c.Parent AS Parent, d.ID, d.CXL, level = level + 1
FROM CTE AS c
INNER JOIN Data AS d ON c.ID = d.CXL
)
SELECT Parent AS OriginalID, ID AS GoodID
FROM CTE AS c
WHERE level = (SELECT MAX(level) FROM CTE WHERE Parent = c.Parent)
CTE
的锚点查询选择启动EACH链的所有原始ID,即具有CXL NULL
的ID。然后我们递归地构建每个链,保留Parent
字段并使用level
,以便能够在最终查询中使用MAX
来识别链的末尾。
答案 2 :(得分:1)
您可以按照以下伪代码的顺序执行此操作: