【问题标题】:recursive query Sort递归查询排序
【发布时间】:2012-09-24 07:50:08
【问题描述】:

我有一个标准表,它定义了父、子类别关系......就像这样。

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

输出是这样的图片:

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

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

我的查询很好,它按预期返回结果...唯一的挑战是我想使用表中的 SORT 列对最后一个节点进行排序,最后一个节点可以有 3 或 4 个我想要排序的子节点,所有节点最后一个节点上方是它的父节点(它们的顺序已经正确)。

我想要这样的输出.... Internet > ISP's > CableVision (1) : Verizon (2) 如您所见 CableVision 和 Verizon 的排序值为 1 & 然后 2,现在假设我们有购物 > 优惠券 > Macys(0):Sears (2),同样的事情......我希望对 Macys & Sears 进行分类......而且它很漂亮 显然他们的父母是购物 > 优惠券。

@Richard aka cyberkiwi,在应用您的代码后,我对类别表的排序非常随机。输出低于

【问题讨论】:

  • 我不同意它是随机的。 11,13,14 都是叶子。它们首先出现在分支之前(1,12 是分支),甚至在它们内部进行排序。同样,1_3 和 1_4 出现在 1_2_* 之前,因为它们是叶子,并且(1_3/1_4 是内部排序的)。如果您想得到满足您期望的答案,您需要学会首先告诉您的期望。从最后一张图片开始,不要只是告诉我们它是错误的。告诉我们它应该是什么样子。
  • 如果我无法正确解释,我深表歉意。请查看 ID“1”及其排序值(即 1),它是父级,它应该是顶级父级类别。 ID“2”也应该在 ID“3”之前,如果您查看它们的排序列值,您会发现排序已关闭。
  • 我有一种感觉,在您发布一张显示上一张图片中给出的确切样本所需的确切结果的图片之前,您不会看到对此问题采取任何行动。

标签: sql tsql


【解决方案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 ;

【讨论】:

  • 是的,出现错误:列名“路径”无效。我认为我们已经到了那里,前提是我可以将孩子放在他们的顶级类别下。
  • 无论我想做什么,它甚至可能吗?我想在保持父子关系的同时基于 Database Driven SORT 列进行排序。我不介意是否必须更改表/查询设计。
【解决方案2】:

这个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

【讨论】:

  • 呵呵,我们的思路是一样的:)
  • 这破坏了整个表的排序,我的查询很好,它按预期返回结果......唯一的挑战是我想使用表中的 SORT 列对最后一个节点进行排序,最后一个节点可以有 3 或 4 个我要排序的子节点,最后一个节点之上的所有节点都是它的父节点(它们的顺序已经正确)。
  • 是的,我试过了,如果我通过一个类别,它就可以工作。例如,PARENT=12。我想返回所有类别及其子项。以你的例子......所有的父母都在TOP,然后所有的孩子都在他们之下。如果查询可以返回仅基于 SORT 列排序的最后一个叶子的树类型输出,那就太好了。
  • 我想要这样的输出.... Internet > ISP's > CableVision (1) : Verizon (2) 如您所见 CableVision 和 Verizon 的排序值为 1 和 2,现在假设我们有 Shopping > Coupons > Macys(0) : Sears (2),同样的事情....我希望对 Macys & Sears 进行排序...而且很明显他们的父母是 Shopping > Coupons。
猜你喜欢
  • 1970-01-01
  • 2019-09-27
  • 2021-12-24
  • 2020-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-07
  • 2014-08-12
相关资源
最近更新 更多