Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/78.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 父母和子女的预排序_Sql_Tsql_Sorting_Preorder - Fatal编程技术网

Sql 父母和子女的预排序

Sql 父母和子女的预排序,sql,tsql,sorting,preorder,Sql,Tsql,Sorting,Preorder,鉴于以下数据: 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或我

鉴于以下数据:

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

这确实使用了CTE,但希望我能解释它们的用法:

;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就是您当前查询的所有内容。您应该能够将您现有的查询放在其中,可能有一个扩展的列列表,并且一切都应该正常工作

Reord解决了我的一个问题,但可能不需要它-如果您的实际数据确实表明id值的顺序正确,那么我们可以忽略排序,然后删除Reord并用id替换对rn的引用。但是这个CTE可以确保父级的子级尊重排序列

最后,hier CTE是这个解决方案的核心——对于每一行,它都在为该行构建一个新的CTE——从子级开始,在树的后面工作,直到我们找到根为止

一旦完成CTE,我们将返回现有的查询,这样我们就可以从那里获取数据,但是可以使用hierarchyid执行适当的排序-该类型已经知道如何正确排序层次数据

结果:

id          parent      sort
----------- ----------- -----------
1           NULL        0
3           1           0
5           3           0
6           5           0
4           1           1
2           NULL        1
7           2           0
结果显示了hier中的“零件”列,这可能有助于您了解CTE的构造:

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/

您可能还想将最终选择更改为仅从hier中选择*,以了解CTE的工作原理

我最终进入了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”,他的直系子女的排序为“000000000100000001”,孙子的排序为“00000000010000000100000001”等等。他的兄弟姐妹从“0000000002”开始,所以在所有01记录之后出现。

你需要一个递归CTE。好吧,如果我这样做,我会这样做,但是从哪里开始呢?编辑您的问题并包含您现在使用的代码。我们是否保证任何孩子的id值始终高于他们各自的父母?也就是说,将6s父项更改为7而不是5将是一个我们不必处理的数据集?