我'm using PostgreSQL' s Ltree模块用于存储分层数据 . 我希望检索按特定列排序的完整层次结构 .
请考虑下表:
votes | path | ...
-------+-------+-----
1 | 1 | ...
2 | 1.1 | ...
4 | 1.2 | ...
1 | 1.2.1 | ...
3 | 2 | ...
1 | 2.1 | ...
2 | 2.1.1 | ...
4 | 2.1.2 | ...
... | ... | ...
在我当前的实现中,我将使用 SELECT * FROM comments ORDER BY path
查询数据库,它将返回整个树:
Node 1
-- Node 1.1
-- Node 1.2
---- Node 1.2.1
Node 2
-- Node 2.1
---- Node 2.1.1
---- Node 2.1.2
但是,我想按 votes
排序(不是 id
,这是按 path
排序的数量) . 每个深度级别都需要独立排序,正确的树形结构保持不变 . 会返回以下内容的东西:
Node 2
-- Node 2.1
---- Node 2.1.2
---- Node 2.1.1
Node 1
-- Node 1.2
---- Node 1.2.1
-- Node 1.1
Postgres' WITH RECURSIVE
可能是合适的,但我不确定 . 有任何想法吗?
2 回答
你在
WITH RECURSIVE
的正确轨道上 .具有递归CTE的解决方案
重点
关键部分是用
votes
的值替换路径的每个级别 . 因此,我们最后组装了一列我们可以ORDER BY
. 这是必要的,因为路径具有未知深度,我们无法通过静态SQL中的未知数量的表达式进行排序 .为了获得稳定的排序,我使用to_char()将
votes
转换为带有前导零的字符串 . 我在演示中使用七位数,适用于低于10.000.000的投票值 . 根据您的最高投票数量进行调整 .在最后
SELECT
我排除所有中间状态以消除重复 . 只剩下max(sort)
的最后一步 .这适用于带有递归CTE的标准SQL,但对于大型树来说效率不高 . plpgsql函数以递归方式更新临时表中的排序路径而不创建临时欺骗可能会表现得更好 .
仅适用于安装的ltree module . 函数subltree(...)和nlevel( . )以及ltree日期类型不是标准PostgreSQL的一部分 .
我的测试设置,方便您查看:
PL / pgSQL表函数做的一样
大树应该更快 .
呼叫:
请阅读manual about setting temp_buffers .
我很感兴趣,它可以更快地显示你的真人生活数据 .
降序
结果是
ASC
结果是