递归查询排序

时间:2012-09-24 07:50:08

标签: sql tsql

我有一个标准表,其中包括父类,子类别关系......就像这样。

id, parent, catName, sort

我使用以下查询来创建递归树

;WITH cte AS (
    SELECT 0 AS lvl, id, catName, parent,levels,sort,
        CAST(id AS VARCHAR(128)) AS path
    FROM CategoriesMap WHERE parent =0
    UNION ALL
    SELECT p.lvl + 1, c.id, c.catName, c.parent,c.levels,c.sort,
        CAST(p.path + '_' + CAST(c.id AS VARCHAR) AS VARCHAR(128))
    FROM CategoriesMap c
    INNER JOIN cte p ON p.id = c.parent
)
SELECT 
    id, 
    catName AS catName, 
    lvl,
    levels,
    path,
    parent,
    sort
FROM cte 
ORDER BY path

输出如下图所示:

enter image description here

查找值为ASP.NET&的行。 CLASSIC ASP,这些是该技术的最后一片叶子(儿童)>软件(父母),我想对任何给定父母(最后一个父母)的最后一个孩子进行排序。对于给定节点(最后一个孩子),我可以有多个父母。 我关心的是使用“排序”列对最后的孩子(叶子)进行排序。

所以基本上“经典Asp”应该在“Asp.Net”之前(我的图片中的最后一列是SORT专栏)。

我的查询很好,它按预期返回结果...只有challenege是我想要使用表中的SORT列排序最后一个NODE,最后一个节点可以有3或4个我要排序的子节点,所有节点在最后一个节点上面是它的父节点(已经是正确的顺序)。

  

我想要这样的输出....互联网> ISP的> CableVision(1):   Verizon(2),你可以看到CableVision& Verizon的排序值为1   &安培;然后2,现在让我们说购物>优惠券>梅西斯(0):西尔斯   (2),同样的事情....我想要Macys&西尔斯要整理......而且漂亮   明显他们的父母是购物>优惠券。

@Richard aka cyberkiwi,在应用你的代码之后,我对Categories表的排序非常随机。输出低于 enter image description here

2 个答案:

答案 0 :(得分:1)

SQL Fiddle应该可以满足您的需求。 诀窍就在于你将树叶和树枝混合在一起。在我的解决方案中,叶子总是出现在分支之前和叶子内(即使与分支混合在一起),当然它们按sort列排序。

DDL

create table CategoriesMap(
    id int, parent int, catname varchar(20), sort int);
insert CategoriesMap select
    1, 0, 'Activities', null union all select
    2, 0, 'Property', null union all select
    3, 2, 'For rent', null union all select
    4, 2, 'For sale', null union all select
    12, 0, 'Technology', 3 union all select
    15, 12, 'Hardware', null union all select
    21, 12, 'Phones', null union all select
    22, 15, 'Computers', null union all select
    18, 12, 'Software', null union all select
    19, 18, 'Asp.net', 2 union all select
    20, 18, 'SQL', 3 union all select
    23, 18, 'Php', 4 union all select
    24, 18, 'Classic ASP', 1;

查询

;WITH leaves AS (
    SELECT A.id
      FROM CategoriesMap A
 LEFT JOIN CategoriesMap B ON A.id=B.parent
     WHERE B.id is null
)
,cte AS (
    SELECT 0 AS lvl, id, catName, parent,sort,
           CAST(id AS VARCHAR(MAX)) AS path,
           '/'+CAST(id AS VARCHAR(MAX))+'/' AS hier
      FROM CategoriesMap
     WHERE parent =0
 UNION ALL
    SELECT p.lvl + 1, c.id, c.catName, c.parent,c.sort,
           p.path + '_' + CAST(c.id AS VARCHAR(MAX)),
           p.hier + CAST(c.id AS VARCHAR(MAX)) + '/'
      FROM CategoriesMap c
      JOIN cte p ON p.id = c.parent
)
    SELECT c.id,
           c.catName,
           c.lvl,
           --levels,
           c.path,
           --c.hier,
           c.parent,
           c.sort
      FROM cte c
 LEFT JOIN leaves l on l.id=c.id
  ORDER BY CASE WHEN l.id is null
                then cast(hier as hierarchyid)
                else cast(hier as hierarchyid).GetAncestor(1)
                END,
           CASE WHEN l.id is null then 0 else 1 end,
           sort

答案 1 :(得分:1)

延迟计算path一个级别,因此最终结果集的父路径(ppath)可用:

;WITH cte AS (
    SELECT 0 AS lvl, id, catName, parent,levels,sort,
        CAST('' AS VARCHAR(128)) AS ppath
    FROM CategoriesMap WHERE parent =0
    UNION ALL
    SELECT p.lvl + 1, c.id, c.catName, c.parent,c.levels,c.sort,
        CAST(p.ppath + '_' + CAST(p.id AS VARCHAR) AS VARCHAR(128))
    FROM CategoriesMap c
    INNER JOIN cte p ON p.id = c.parent
)
SELECT 
    id, 
    catName, 
    lvl,
    levels,
    CAST(ppath + '_' + CAST(id AS VARCHAR) AS VARCHAR(128)) AS path,
    parent,
    sort
FROM cte
ORDER BY 
    CASE WHEN sort IS NULL
           THEN path
           ELSE ppath
    END
  , sort ;

不确定上面给出错误的原因。这不会:

ORDER BY 
    CASE WHEN sort IS NULL
      THEN CAST(ppath + '_' + CAST(id AS VARCHAR) AS VARCHAR(128))
      ELSE ppath
    END
  , sort ;