我一直在努力优化纯粹在ruby中完成的递归调用。我已将数据移动到postgresql数据库,我想使用postgresql提供的WITH RECURSIVE
函数。
我可以找到的所有示例似乎都使用单个表,例如菜单或类别表。
我的情况略有不同。我有问题和答案表。
+----------------------+ +------------------+
| questions | | answers |
+----------------------+ +------------------+
| id | | source_id | <- from question ID
| start_node (boolean) | | target_id | <- to question ID
| end_node (boolean) | +------------------+
+----------------------+
我想通过相关答案获取所有连接在一起的问题。
我还希望能够在树中采用另一种方式,例如从任何给定节点到树中的根节点。
以图形方式给出问答树的另一个例子:
Q1
|-- A1
| '-- Q2
| |-- A2
| | '-- Q3
| '-- A3
| '-- Q4
'-- A4
'-- Q5
正如您所看到的,一个问题可以有多个外向问题,但它们也可以有多个传入的答案 - 任意对多。
我希望有人有个好主意,或者能指出一些例子,文章或指南。
先谢谢大家。
此致 埃米尔
答案 0 :(得分:1)
这远非理想,但我会在连接上进行递归查询,例如:
WITH RECURSIVE questions_with_answers AS (
SELECT
q.*, a.*
FROM
questions q
LEFT OUTER JOIN
answers a ON (q.id = a.source_id)
UNION ALL
SELECT
q.*, a.*
FROM
questions_with_answers qa
JOIN
questions q ON (qa.target_id = q.id)
LEFT OUTER JOIN
answers a ON (q.id = a.source_id)
)
SELECT * FROM questions_with_answers WHERE source_id IS NOT NULL AND target_id IS NOT NULL;
这给了我结果:
id | name | start_node | end_node | source_id | target_id
----+------+------------+----------+-----------+-----------
1 | Q1 | | | 1 | 2
2 | A1 | | | 2 | 3
3 | Q2 | | | 3 | 4
3 | Q2 | | | 3 | 6
4 | A2 | | | 4 | 5
6 | A3 | | | 6 | 7
1 | Q1 | | | 1 | 8
8 | A4 | | | 8 | 9
2 | A1 | | | 2 | 3
3 | Q2 | | | 3 | 6
3 | Q2 | | | 3 | 4
4 | A2 | | | 4 | 5
6 | A3 | | | 6 | 7
8 | A4 | | | 8 | 9
3 | Q2 | | | 3 | 6
3 | Q2 | | | 3 | 4
6 | A3 | | | 6 | 7
4 | A2 | | | 4 | 5
6 | A3 | | | 6 | 7
4 | A2 | | | 4 | 5
(20 rows)
答案 1 :(得分:1)
实际上你不需要两张桌子。 我想鼓励你分析这个例子。 维护一个表而不是两个表可以省去很多麻烦,特别是在递归查询时。
这个最小的结构包含所有必要的信息:
create table the_table (id int primary key, parent_id int);
insert into the_table values
(1, 0), -- root question
(2, 1),
(3, 1),
(4, 2),
(5, 2),
(6, 1),
(7, 3),
(8, 0), -- root question
(9, 8);
节点是问题还是答案取决于它在树中的位置。当然,您可以向表中添加一个包含节点类型信息的列。
使用此查询获取您的请求的答案(取消注释适当的where
条件):
with recursive cte(id, parent_id, depth, type, root) as (
select id, parent_id, 1, 'Q', id
from the_table
where parent_id = 0
-- and id = 1 <-- looking for list of a&q for root question #1
union all
select
t.id, t.parent_id, depth+ 1,
case when (depth & 1)::boolean then 'A' else 'Q' end, c.root
from cte c
join the_table t on t.parent_id = c.id
)
select *
from cte
-- where id = 9 <-- looking for root question for answer #9
order by id;
id | parent_id | depth | type | root
----+-----------+-------+------+------
1 | 0 | 1 | Q | 1
2 | 1 | 2 | A | 1
3 | 1 | 2 | A | 1
4 | 2 | 3 | Q | 1
5 | 2 | 3 | Q | 1
6 | 1 | 2 | A | 1
7 | 3 | 3 | Q | 1
8 | 0 | 1 | Q | 8
9 | 8 | 2 | A | 8
(9 rows)
关系子 - 父母是明确的,适用于双方。无需存储此信息两次。换句话说,如果我们存储有关父母的信息,则有关儿童的信息是多余的(反之亦然)。它是名为tree
的数据结构的基本属性之一。参见示例:
-- find parent of node #6
select parent_id
from the_table
where id = 6;
-- find children of node #6
select id
from the_table
where parent_id = 6;