0

给定以下数据:

id  |  parent | sort
--------------------
  1 | null    | 0
  2 | null    | 1
  3 | 1       | 0
  4 | 1       | 1
  5 | 3       | 0
  6 | 5       | 0
  7 | 2       | 0

我如何进行预订排序,首先是父母,然后是孩子,然后是孙子等等......?

我正在寻找的排序结果是:1、3、5、6、4、2、7

如果可能的话,我想在不使用 CTE(或我能理解的 CTE)的情况下做到这一点。我现在这样做的方式只是选择每条记录并检查“向上”以查看是否有任何父母、祖父母和曾祖父母。为没有父母的记录(最重要的项目)做一些事情并让它继续直到没有孩子为止更有意义,对吧?

我只是无法解决这个问题......

这是对我的实际查询的过度简化,但我现在正在做的事情是:

SELECT ..some columns ..
FROM table t
LEFT JOIN table tparent WHERE tparent.ID = t.Parent
LEFT JOIN table tgrandparent WHERE tgrandparent.ID = tparent.Parent
LEFT JOIN table tgreatgrandparent WHERE tgreatgrandparent.ID = tgrandparent.Parent
4

2 回答 2

0

我终于投入到 CTE 并让它工作了,这里是查询的基础,如果其他人可能会遇到它。重要的是要注意这sort是一个填充字符串,从开始0000000001并向上计数。

WITH recursive_CTE (id, parentId, sort) 
AS
(
-- CTE ANCHOR SELECTS ROOTS --
SELECT t.ID AS id, t.Parent as parentId, t.sort AS sort
FROM table t 
WHERE t.Parent IS NULL
UNION ALL
-- CTE RECURSIVE SELECTION --
SELECT t.ID AS id, t.Parent as parentId, cte.sort + t.sort AS sort
FROM table t
INNER JOIN recursive_CTE cte ON cte.id = t.Parent
)

SELECT * FROM recursive_CTE
ORDER BY sort

我相信这是使这种查询工作所需的主要部分。如果你确保你达到了必要的指数,它实际上是相当快的。

排序是通过扩展字符串来建立的。因此,父母的排序为“0000000001”,他的直系孩子将有“00000000010000000001”,他的孙子将有“000000000100000000010000000001”等。他的兄弟姐妹从“00000000002”开始,因此在所有01记录之后。

于 2015-01-22T08:45:31.060 回答
0

This does use CTEs, but hopefully I can explain their usage:

;With ExistingQuery (id,parent,sort) as (
select 1,null,0 union all
select 2,null,1 union all
select 3,1   ,0 union all
select 4,1   ,1 union all
select 5,3   ,0 union all
select 6,5   ,0 union all
select 7,2   ,0
), Reord as (
    select *,ROW_NUMBER() OVER (ORDER BY parent,sort) as rn from ExistingQuery
), hier as (
    select id,parent,'/' + CONVERT(varchar(max),rn)+'/' as part
    from Reord
    union all
    select h.id,r.parent,'/' + CONVERT(varchar(max),r.rn) + part
    from hier h
        inner join
        Reord r
            on
                h.parent = r.id
)
select
    e.*
from
    hier h
        inner join
    ExistingQuery e
        on
            h.id = e.id
where
    h.parent is null
order by CONVERT(hierarchyid,h.part)

ExistingQuery is just whatever you've currently got for your query. You should be able to just place your existing query in there (possibly with an expanded column list) and everything should just work.

Reord addresses a concern of mine but it may not be needed - if your actual data is actually such that the id values are indeed in the right order that we can ignore sort then remove Reord and replace the references to rn with id. But this CTE does that work to make sure that the children of parents are respecting the sort column.

Finally, the hier CTE is the meat of this solution - for every row, it's building up a hierachyid for that row - from the child, working back up the tree until we hit the root.

And once the CTEs are done with, we join back to ExistingQuery so that we're just getting the data from there, but can use the hierarchyid to perform proper sorting - that type already knows how to correctly sort hierarchical data.

Result:

id          parent      sort
----------- ----------- -----------
1           NULL        0
3           1           0
5           3           0
6           5           0
4           1           1
2           NULL        1
7           2           0

And the result showing the part column from hier, which may help you see what that CTE constructed:

id          parent      sort        part
----------- ----------- ----------- --------------
1           NULL        0           /1/
3           1           0           /1/3/
5           3           0           /1/3/6/
6           5           0           /1/3/6/7/
4           1           1           /1/4/
2           NULL        1           /2/
7           2           0           /2/5/

(You may also want to change the final SELECT to just SELECT * from hier to also get a feel for how that CTE works)

于 2015-01-21T15:03:48.663 回答