Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/69.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_Postgresql_Tree_Materialized Path Pattern_Django Treebeard - Fatal编程技术网

Sql 搜索物化路径树的最右侧节点

Sql 搜索物化路径树的最右侧节点,sql,postgresql,tree,materialized-path-pattern,django-treebeard,Sql,Postgresql,Tree,Materialized Path Pattern,Django Treebeard,是否可以通过物化路径树的path文本字段进行排序,以找到树的最右侧节点?例如,考虑使用Django TeeeBeLID的代码Python函数的Pyth>MPyNob: def get_最右边的_节点(): “”“返回当前树中最右边的节点。 :rtype:MyNode """ #MyNode是django treebeard的MP_节点的一个子类。 返回MyNode.objects.order_by('-path').first() 从我所有的测试中,它似乎返回了我所期望的,但我不知道如何用数学

是否可以通过物化路径树的
path
文本字段进行排序,以找到树的最右侧节点?例如,考虑使用Django TeeeBeLID的代码Python函数的Pyth>MPyNob:

def get_最右边的_节点():
“”“返回当前树中最右边的节点。
:rtype:MyNode
"""
#MyNode是django treebeard的MP_节点的一个子类。
返回MyNode.objects.order_by('-path').first()
从我所有的测试中,它似乎返回了我所期望的,但我不知道如何用数学来证明它。我还没有找到任何关于在物化路径树上执行此操作的信息

Treebeard的实现在路径中没有分隔符,因此路径 如下所示:
0001
00010001
00010012
,等等。

简短回答:否

演示我在评论中描述的问题

对于此简单设置:

id, path
1,  '1'
2,  '1\2'
3,  '1\3'
4,  '1\4'
5,  '1\5'
6,  '1\6'
7,  '1\7'
8,  '1\8'
9,  '1\9'
10, '1\10'
尝试通过简单排序获取最右边的叶(
id=10
)将失败:

SELECT TOP 1
  id,
  path
FROM hierarchy
ORDER BY path DESC
返回:

id, path
9,  1\9
由于
path
是一个基于文本的列,
1\10
将以降序排序出现在
1\9
之后(请参见小提琴中第二次查询的结果)

即使您开始跟踪深度和路径长度,这通常是便宜且容易跟上的,也完全有可能获得如下路径:

path       depth  length
12\3\11\2  4      9
5\17\10\1  4      9
仍然无法正确排序

即使您使用字母而不是数字,这也只会将问题范围推到第26个孩子,而不是第10个:

我对物化路径操作的熟悉程度不如对嵌套集和邻接列表的熟悉程度,也没有使用django的经验,因此如果有我不知道的方法,我会听从其他人,但几乎可以肯定的是,您必须对
path
列执行某种形式的解析,才能始终获得正确的叶

编辑-解决了排序是否是有效解决方案的问题后,经过一点讨论和思考,下面是关于其他潜在解决方案的一些补充说明:

-“最右边”是一个模糊的术语,当节点可以有两个以上的子节点时(即,树不是二叉树)。如果一个节点有10个子节点,哪些在父节点的左侧,哪些在右侧?必须先定义此条件,然后才能定义问题的解决方案

-一旦为您的问题空间正确定义了“最右边的”节点,请理解最右边的节点不一定位于树的最低级别:

        1
       / \
    1\1   1\2 <= This is the rightmost node
    /
  1\1\1 <= This is the lowest node

此循环将查找当前节点右侧的当前节点的子节点。如果它们存在,它将选择最右边的子级并重复。一旦到达右侧没有子节点的节点,它将返回当前节点,因为它已找到树(或子树)最右侧的节点以
startNode
作为其根。

您可以使用@Paul解释的方法进行一些修改。您可以在每个数字前面附加
0
,并且每个路径的长度可以一致

可以将节点分配为以下路径:

id |  path
-----------------
1  |  '01'
2  |  '01\01'
3  |  '01\02'
4  |  '01\03'
5  |  '01\04'
6  |  '01\04\01'
7  |  '01\04\02'
8  |  '01\04\03'
9  |  '01\05\01'
10 |  '01\05\02'
11 |  '01\05\03'
12 |  '01\05\04'
如果具有最大子节点数的节点的子节点数小于100,则可以使用上述示例

如果它在100到1000之间,那么您可以添加一个额外的
0
作为
001\003\002\005
,就像wise一样

然后您可以得到最右边的节点
12
as

SELECT TOP 1 id
FROM tree
ORDER BY path DESC
你可以在这里找到演示。
编辑:Paul Griffin正确地指出我的答案不可靠,因为它假设节点将低于某个值。这是一个更好的尝试,在Denis de Bernardy的深度函数上加入两个旋转

使用两个排序条件,一个用于深度,另一个用于转换为整数的最左侧节点的值:

SELECT path, 
       length(regexp_replace(path, '[^/]+', '', 'g')) as depth,
       regexp_replace(path, '^.*/', '')::int as last       
FROM test 
ORDER BY depth DESC, last DESC;
这将把具有最高值的最深节点放在顶部

是否可以通过物化路径树的路径文本字段进行排序,以找到树的最右侧节点

否。例如,如果节点路径存储为
'/1/3/6/2'
,请考虑:

/1
/1/3
/1/3/6/2
/1/3/6/5
/1/3/6/21
/1/40
参考Paul的答案,以了解上述分类不起作用的原因

然而,所有的希望都没有丧失。如果您正在搜索“最右边的节点”,我假设您指的是树中最深的节点,您可以简单地计算分隔符。例如:

select length(regexp_replace('/1/3/6/2', '[^/]+', '', 'g')) as depth;
如果您希望达到最大值,请使用以下方法:

order by length(regexp_replace(path, '[^/]+', '', 'g')) desc
。。。或等效的python代码。索引选项包括为同一表达式编制索引,或将结果存储在单独的深度字段中并对其编制索引

如果您仍然对ID的实际值感兴趣,那么上面的数字通常与ID对应,因此使用该列进一步排序。如果它们不同,则使用不同的正则表达式提取最右边的图形,并将其转换为整数,以便自然(1,11,2)排序,而不是按字典顺序(1,11,2):


如果路径存储在varchar列中,我会担心像
4\3\1\11
这样的路径最终会出现在像
4\3\1\5
这样的路径之前,这在技术上应该是第一位的。这并不是对您的答案的敲打,更像是对后代的警告。。。如果您确信您的数据永远不会超过设定的界限,那么这些解决方案是可行的。但是,您最好对如此依赖数据的解决方案保持警惕。在过去,我经常被改变规格或数据集所困扰,这些规格或数据集使magnitute的数量超过了预期,并开始打破这样的解决方案。在这一点上,修复/重构/维护几乎是不可能的,而且比刚开始编写更通用的解决方案要耗费更多的时间和金钱。如果级别超出限制,则重构
order by length(regexp_replace(path, '[^/]+', '', 'g')) desc
select regexp_replace('/1/3/6/2', '^.+/', '')::int as value;