我们有以下树形结构。目的是使用postgresql查询在数据库中构造一个表。 该表应包含以下信息。第一列包含节点。 第二个包含父节点。
|--node1.1.1
|-node1.1--|
| |--node1.1.2
|
|
|
node1--|-node1.2--|--node1.2.1
|
|
|
|
|-node1.3
下面是查找将生成初始表的查询:
CREATE TABLE tree
( node character varying NOT NULL,
node_parent character varying,
CONSTRAINT tree_pkey PRIMARY KEY (node),
CONSTRAINT fk_ FOREIGN KEY (node_parent)
REFERENCES tree (node) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
WITH (
OIDS=FALSE
);
ALTER TABLE tree
OWNER TO postgres;
INSERT INTO tree(node, node_parent) VALUES ('node1', null);
INSERT INTO tree(node, node_parent) VALUES ('node1.1', 'node1');
INSERT INTO tree(node, node_parent) VALUES ('node1.2', 'node1');
INSERT INTO tree(node, node_parent) VALUES ('node1.3', 'node1');
INSERT INTO tree(node, node_parent) VALUES ('node1.1.1', 'node1.1');
INSERT INTO tree(node, node_parent) VALUES ('node1.1.2', 'node1.1');
INSERT INTO tree(node, node_parent) VALUES ('node1.2.1', 'node1.2');
然后从这个表(树)我们的目标是生成下表。查询应为每个组合节点返回子节点列表。此查询应生成与下面示例相同的结果。 为此,我们提出了以下查询。
SELECT node, node_parent FROM tree t where not (node in(select distinct node_parent from tree where not node_parent is null))
union all
SELECT tn2.node, tn1.node_parent FROM tree tn1 join tree tn2 on tn1.node = tn2.node_parent where not tn1.node_parent is null and not (tn2.node in(select distinct node_parent from tree where not node_parent is null))
结果:
我们提出的查询问题是它不是通用的,并不适用于所有情况(此查询仅适用于我们有一个深度等于3的树的情况)。我们想要一个适用于所有情况的查询。
答案 0 :(得分:2)
看看with statement。您的最终查询将如下所示。
with recursive hierarchy(node, node_parent, level) as (
select node, node_parent, 0
from tree
where node_parent is null
union all
select t.node, t.node_parent, level + 1
from tree t
join hierarchy h on t.node_parent = h.node)
select *
from hierarchy;
答案 1 :(得分:1)
使用标准sql无法创建具有可变深度的查询。
所以你可以按照以下方式之一:
创建一个带有两个节点的函数,如果它们是亲属则返回true(所以如果可以从node1转到node2,父节点传递父节点。并在查询中使用此函数。
< / LI>使用递归查询
更改数据库而不是标准关系数据库使用图形数据库,该图形数据库本身可以提供函数来导航整个图形而不受深度限制。
请注意,前两个选项可能非常繁重,因为不会为此类查询编写关系数据库。
答案 2 :(得分:0)
感谢您的所有贡献。多亏了我们已成功解决了以下问题:
SELECT DISTINCT
ml.list_id
,info_risk_code as c_rr
,list_risk_code as a_rr
FROM
my_list AS ml
INNER JOIN my_info_list AS mil ON mil.list_id = ml.list_id
INNER JOIN my_info AS mi ON mil.info_id = mi.info_id
WHERE
(
(info_risk_code = '600' OR info_risk_code = '360')
AND (NOT list_risk_code = '600' AND NOT list_risk_code = '360')
)
OR
(
(NOT info_risk_code = '600' AND NOT info_risk_code = '360')
AND (list_risk_code = '600' OR list_risk_code = '360')
)