你怎么会找到好的'涉及取消时的ID以及启动它的原始ID?

时间:2015-03-26 20:46:55

标签: sql sql-server

请不要在没有阅读的情况下将问题标记为重复。我发布了一个类似的问题,但是,由于解决方案更加复杂,小型,次要的修改,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

3 个答案:

答案 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

Here's your SQLFiddle

这假设取消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来识别链的末尾。

SQL Fiddle Demo

答案 2 :(得分:1)

您可以按照以下伪代码的顺序执行此操作:

  • 创建剩余表格,好
  • 将数据复制到剩余的
  • 将剩余的所有行复制到Good
  • 中,这些行具有在CXL列中无处出现的ID值
  • 从剩余
  • 中删除这些行
  • 虽然剩余有> 0行
    • 内部联接Good.CXL = Remaining.ID
    • 将联接中的行的Good.CXL更新为Remaining.CXL
    • 从剩余
    • 中删除联接中的行