【问题标题】:Controlling the sibling order under recursive CTE?在递归 CTE 下控制兄弟顺序?
【发布时间】:2013-08-03 19:22:00
【问题描述】:

我有一个 CTE 查询,用于查找主叶和子叶。但我无法控制两个兄弟姐妹之间的叶子选择顺序

表中的每一行都声明为:

(childID INT ,parentID INT ,NAME NVARCHAR(30),location int)

其中location 是优先排序IFF 他们是兄弟姐妹。

所以我有这个树结构:这些对有一个位置优先级:

例如:

`a` ( location=1) should be before `f` (location=2)
`b` ( location=1) should be before `e` (location=2)
`d` ( location=1) should be **before** `c` (location=2)

问题是我似乎必须首先 order by childID 才能看到正确的结构(sibling unsorted)。

但是 - 我的 order by 应该是什么样子才能看到正确的结构(&& 同级排序)?

(在我的例子中:d 应该在 c 之前)

Here is the working query which yields all the tree leafs ( unsorted siblings)

附言childID 表示有关排序的任何内容。它只是一个占位符。正如我所说,两兄弟之间的位置是location 列。(这里,childId 是排序的,因为那是我插入行的顺序...

【问题讨论】:

  • @downvoter ,在没有评论或解释这样详细的问题的情况下投反对票 - 不是本网站的精神。 - 报告。

标签: sql-server recursion sql-order-by common-table-expression


【解决方案1】:

您可以计算 CTE 中树节点的路径并将其用于排序

;WITH CTE AS(
   SELECT childID, parentID, 0 AS depth, NAME , location,
         cast(location as varbinary(max)) path
   FROM   @myTable
   WHERE   childID = parentID 
    UNION ALL
    SELECT  TBL.childID, TBL.parentID,
           CTE.depth + 1 , TBL.name ,TBL.location,
           cte.path + cast(TBL.location as binary(4))
    FROM   @myTable AS TBL
            INNER JOIN CTE  ON  TBL.parentID = CTE.childID
    WHERE   TBL.childID<>TBL.parentID
)
SELECT depth, childID, parentID, location, REPLICATE('----', depth) + name
FROM CTE
ORDER BY path

【讨论】:

  • 那些技巧之类的让我觉得真的很愚蠢。 :-)(但我很高兴学习这种技术)。-- p.s.它正在工作。
  • 通常location 左填充零以确保每个级别的宽度都是固定的,例如Right( '00000' + Cast( Tbl.Location as VarChar(6) ), 6 )。这样可以避免按字母顺序排列数字的任何奇怪之处。
  • @HABO,对,谢谢,已更正(但我使用的有点不同,保留了相同的逻辑,但视觉上更短了一点)
  • @RoyiNamir,HABO 做了重要通知,请查看更新的答案,这样当兄弟姐妹数量足够大时,您就不会得到例如1, 10, 2, 20, 3, 4, 5 ..
  • @i-one 我不明白你的第一个解决方案的问题这对我来说很好data.stackexchange.com/stackoverflow/query/edit/127299 请解释
【解决方案2】:

以下是 i-one 的答案,应 Royi Namir 的要求修改为使用左侧填充的数字字符串作为路径:

;WITH CTE AS(
   SELECT childID, parentID, 0 AS depth, NAME , location,
         Cast( Right( '00000' + Cast( Location as VarChar(6) ), 6 ) as  VarChar(1024) ) as Path
   FROM   @myTable
   WHERE   childID = parentID 
    UNION ALL
    SELECT  TBL.childID, TBL.parentID,
           CTE.depth + 1 , TBL.name ,TBL.location,
           Cast( cte.Path + '.' + Right( '00000' + Cast( Tbl.Location as VarChar(6) ), 6 ) as VarChar(1024) )
    FROM   @myTable AS TBL
            INNER JOIN CTE  ON  TBL.parentID = CTE.childID
    WHERE   TBL.childID<>TBL.parentID
)
SELECT depth, childID, parentID, location, REPLICATE('----', depth) + name
FROM CTE
ORDER BY path

注意:未经测试且在假期中编写。

分隔符 (.) 不是必需的,但可以使结果值更易于阅读,并且可以简化一些操作,例如寻找共同的子路径。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2012-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多