我有一个PostgreSQL表,其中包含几个条件及其各自的后继条件。有些条件有几个继承者,这些继承者也可能有几个接班人。因此,目标是提取所有可能的条件链,以实现数据中的树形图。 该表如下所示:
id | con | succ
----|-----|-----
1 | a | b
2 | a | c
3 | a | d
4 | b | c
5 | b | f
6 | c | e
7 | c | g
8 | c | h
9 | d | h
10 | d | i
我仍然不知道如何在最后存储单链,但我需要起点(a),相应的终点以及起点和终点之间的所有节点。 我很感谢有关如何存储链以及如何提取它们的各种建议。
更新:
这是我数据的摘录:
ID | parent_ID
----|----------
403 | 302
404 | 2xx
405 | 303
406 | 304
407 | 304
408 | 2xx
409 | 305
501 | 2xx
502 | 305
503 | 2xx
504 | 2xx
505 | 2xx
506 | 305
507 | 2xx
508 | 306
509 | 2xx
510 | 307
511 | 308
512 | 308
513 | 308
514 | 309
515 | 310
600 | 5xx
您会看到一些父ID不是ID本身,而是ID组('全部以2开头')。现在的问题是如何使递归查询运行或如何使递归查询处理'2xx'。值存储为字符。而不是'2xx'也可以使用另一种符号。
答案 0 :(得分:2)
有效地查询存储在数据库中的树和图形相关数据是一个相当广泛的主题。
就存储而言,请注意存储(id, parent_id)
对通常会更好(如广泛接受)选项。
问题是如何查询它,更重要的是如何有效地进行查询。
树木的主要选项包括:
WITH查询:http://www.postgresql.org/docs/current/static/queries-with.html
优点:内置,在处理小型设备时工作正常 缺点:对于较大的集合不能很好地扩展
MPTT,又名已预订的树木:http://en.wikipedia.org/wiki/Tree_traversal
优点:最快的树木读数
缺点:写入速度慢,除非您逐行执行行,否则难以维护
树的嵌套集(或间隔):http://en.wikipedia.org/wiki/Nested_set_model
优点:快速读取树木
缺点:比MPTT更快,但仍然缓慢,不易理解
Postgres的ltree类型:http://www.postgresql.org/docs/current/static/ltree.html
优点:内置,可索引的
缺点:不是ORM友好
我将MPTT的混合变体添加到列表中:如果使用float
索引实现MPTT,则在树中移动物体时可以不更新任何内容,这样可以快速完成任务。但是,维护起来要困难得多,因为当两个索引之间的差异太小时可能会发生冲突 - 当发生这种情况时,您需要重新索引树的足够大的子集。
对于图表,WITH
查询也有效。还存在MPTT和嵌套集的变体;例如GRIPP index。这是一个研究和新索引方法仍然非常活跃的领域。
答案 1 :(得分:0)
您最好的方法是使用ltree
数据类型。请参阅documentation here。这确实需要你稍微改造你的表结构。如果这不是一个选项,你应该看看recursive with-queries,它可以 - 乍一看 - 使用你当前的表结构,但查询将提供的数据格式不像{{1数据。
最好使用递归的with-query将当前表转换为ltree变量。首先,您需要创建一个新表来保存ltree列:
ltree
然后运行递归查询并将结果插入新表中:
CREATE TABLE tree_list (
id int,
chain ltree
);
您将注意到,您在上面提供的10行数据将产生13个链,因为从a到e,g和h中的每一个都有多条路径。此查询应该适用于几乎无限深度的树。
WITH RECURSIVE build_tree(id, chain) AS (
SELECT id, con::ltree || succ
FROM tree
WHERE con = 'a'
UNION ALL
SELECT tree.id, build_tree.chain || tree.succ
FROM tree, build_tree
WHERE build_tree.chain ~ ('*.' || tree.con)::lquery)
INSERT INTO tree_list SELECT * FROM build_tree;