【问题标题】:SQL Server: how to achieve the tree nested level sortSQL Server:如何实现树的嵌套级别排序
【发布时间】:2016-06-07 00:49:40
【问题描述】:

我有基于树结构的记录(父子关系),我想实现嵌套级别排序。基本上,我需要基于级别的排序以及需要 维护父子关系(排序子级)。我曾尝试使用 CTE,但我只能实现基于级别的排序,但问题是无法实现 父子关系。

我试过下面的查询

SELECT * FROM EMP WHERE PARENTID IS NULL order by

CASE WHEN PARENTID IS NULL THEN 
    lower(name)
ELSE 
    (SELECT lower(name) FROM EMP WHERE ID=ROOTID) END  DESC,
ROOTID, JOBLEVEL, NAME 

实际表格

ID       PARENTID       NAME        FULLPATH   LEVEL  ROOTID
_____________________________________________________________               
1        NULL            AA             1        1      1
2        1               BB            1.2       2      1
3        1               ZZ            1.3       2      1
4        1               HH            1.4       2      1
5        2               RR            1.2.5     3      1
6        2               CC            1.2.6     3      1
7        3               DD            1.3.7     3      1
8        3               UU            1.3.8     3      1
9        4               GG            1.4.9     3      1
10       4               LL            1.4.10    3      1
11      NULL             KK            11        1      11
12      11               VV            11.12     2      11

实际的树结构

AA
    BB
    ZZ
    HH
        RR
        CC
        DD
        UU
        GG
        LL
KK
    VV

预期的表格升序

ID   PANTID     NAME    FULLPATH      LEVEL
____________________________________________            
1       NULL    AA          1           1

2       1       BB          1.2         2
6       2       CC          1.2.6       3
5       2       RR          1.2.5       3

4       1       HH          1.4         2
9       4       GG          1.9.4       3
10      4       LL          1.4.10      3

3       1       ZZ          1.3         2
7       3       DD          1.3.7       3
8       3       UU          1.3.8       3

11      NULL    KK          11          1
12      11      VV          11.12       2

预期的升序树结构

AA  
    BB  
        CC
        RR
    HH
        GG
        LL
    ZZ
        DD
        UU
KK
        VV

预期的表格降序

ID  PARENTID        NAME     FULLPATH     LEVEL
________________________________________________
11      NULL        KK          11          1
12      11          VV          11.12       2

1       NULL        AA          1           1

3       1           ZZ          1.3         2
7       3           DD          1.3.7       3
8       3           UU          1.3.8       3

4       1           HH          1.4         2
9       4           GG          1.9.4       3
10      4           LL          1.4.10      3

2       1           BB          1.2         2
6       2           CC          1.2.6       3
5       2           RR          1.2.5       3

预期的下降树结构

KK
    VV
AA  
    ZZ
        UU
        DD
    BB  
        RR
        CC          
    HH
        LL
        GG

【问题讨论】:

标签: sql sql-server sql-server-2008 tsql


【解决方案1】:

FULLPATH 和实际字段吗?您可以使用一些巧妙的字符串操作将其转换为完全按照您想要的排序的字符串(例如用 6、7、8 替换所有整数,但是您希望有很多整数需要零填充版本)。例如,如果您知道您永远不会达到 100 万个 ID,则将 1 转为 00000001,将 1.2 转为 0000001.0000002 等。这应该完全按照您的意愿进行排序。

但是,这将按 ID 而不是按名称对相同级别的 ID 进行排序。如果这是您未提及但您的示例似乎这样做的规范的一部分,则它将不起作用。

我能想到的唯一其他方法与假设合理的最大嵌套级别有关。在这种情况下,您可以将每个级别分解为自己的子查询或查看并重新集成为链接表。

【讨论】:

  • 是的。我在插入时填充了级别和完整路径。在这里,不仅名称而且其他列也可用
【解决方案2】:

递归 CTE 是您应该使用的工具。这是适合您的工作示例。请注意,您的 FULLPATH、LEVEL 和 ROOTID 字段是多余的。

declare @emp table (id int,parentId int, name varchar(10))--your table
insert @emp values                --test values
(1   ,     NULL    ,        'AA'), 
(2,        1,               'BB'),
(3,        1,               'ZZ'), 
(4,        1,               'HH'), 
(5,        2 ,              'RR'), 
(6,        2,               'CC'), 
(7,        3,               'DD'), 
(8,        3,               'UU'), 
(9,        4,               'GG'), 
(10,       4,               'LL'), 
(11,      NULL       ,      'KK'), 
(12,      11,               'VV') 

;with emps as (
--anckor query
select id, parentid, name, 
format(id,'00000') sort, --format is sql 2012+ feature
1 lvl, --calc levels
format(100000-id,'00000') descsort --trick for desc sort
from @emp where parentId is null
union all --must be ALL
--recursive query
select e.id, e.parentid, e.name, sort+format(e.id,'00000') sort,  lvl+1,descsort+format(e.id,'00000')
from @emp e 
inner join emps on e.parentId=emps.id
)
select * from emps
order by sort  --or **by descsort** if you want "desc"

为 2012 年之前的版本编辑

stuff('00000',5-len(cast(id as varchar)),1000,cast(id as varchar)) 

更新为按名称排序

;with emps as (
select id, parentid, name, 
cast(left(name,2)+stuff('00000',5-len(cast(id as varchar)),1000,cast(id as varchar)) as varchar(max)) sort, --2008
--format(id,'00000') sort, 
1 lvl, 
format(100000-id,'00000') descsort -- use sort field as example
from @emp where parentId is null
union all
select e.id, e.parentid, e.name, 
sort+left(e.name,2)+stuff('00000',5-len(cast(e.id as varchar)),1000,cast(e.id as varchar)),
--sort+format(e.id,'00000') sort,  
lvl+1,descsort+format(e.id,'00000')
from @emp e 
inner join emps on e.parentId=emps.id
)
select * from emps
order by sort -- descsort 

这是用于降序排序

;with emps as (
select id, parentid, name, 
cast(left(name,2)+stuff('00000',5-len(cast(id as varchar)),1000,cast(id as varchar)) as varchar(max)) sort, --2008
--format(id,'00000') sort, --2012
1 lvl, 
cast(stuff('00000',6-len(cast((100000-id) as varchar)),1000,cast((100000-id) as varchar))+left(name,2) as varchar(max)) descsort --2008
--format(100000-id,'00000') descsort -- use sort field as example
from @emp where parentId is null
union all
select e.id, e.parentid, e.name, 
sort+left(e.name,2)+stuff('00000',5-len(cast(e.id as varchar)),1000,cast(e.id as varchar)),
--sort+format(e.id,'00000') sort,  
lvl+1,
descsort+stuff('00000',6-len(cast(100000-e.id as varchar)),1000,cast(100000-e.id as varchar))+left(e.name,2)
--format(e.id,'00000')
from @emp e 
inner join emps on e.parentId=emps.id
)
select * from emps
order by --sort desc-- 
descsort 

【讨论】:

  • 我使用的是 sql server 2008。我不能使用 format()。我尝试使用+(连接)。它没有帮助我。我无法实现排序(嵌套级别)
  • 我尝试了一些东西,但名称没有排序。此外,我们不能保证 id 是序列,例如:父 id 30 和子 id 20。
  • “我们不能保证 id 是序列”。没关系。如果 id 大于 99999,则在填充掩码中添加 000。
  • 我试过了,asc 查询工作正常。但是,降序不适用于名称。我尝试了以下一个演员(左(ISNULL(名称,''),2)+东西(演员(100000-id as varchar),5-len(cast(id as varchar)),1000,'00000')作为varchar (max)) 作为 descsort
  • 能否请您也给我降序查询
猜你喜欢
  • 2023-03-03
  • 1970-01-01
  • 2015-02-14
  • 1970-01-01
  • 2019-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-23
相关资源
最近更新 更多