我在 Oracle 中遇到递归查询问题。
假设我有一个带有结构的表“NAMES”:
财产 | 姓名 | 参考 |
---|---|---|
0 | 迈克 | 1 |
1 | 约翰 | 4 |
1 | 詹姆斯 | 4 |
1 | 罗伯特 | 4 |
4 | 迈克尔 | 5 |
5 | 大卫 | 6 |
6 | 马克 | 空 |
和简单的递归查询:
WITH rec as
(
SELECT N_1.PROPERTY, N_1.NAME, N_1.REFERENCE
FROM NAMES N_1
WHERE PROPERTY = 0
UNION ALL
SELECT N_2.PROPERTY, N_2.NAME, N_2.REFERENCE
FROM NAMES N_2
JOIN rec r ON T_2.PROPERTY = r.REFERENCE
)
SELECT NAME FROM rec;
女巫给出:
姓名 |
---|
迈克 |
詹姆斯 |
约翰 |
罗伯特 |
迈克尔 |
迈克尔 |
迈克尔 |
大卫 |
大卫 |
大卫 |
马克 |
马克 |
马克 |
因此,一切正常。但问题是:对于迈克 - 找到 3 条记录:詹姆斯、约翰、罗伯特(没关系) - 然后为他们每个人找到迈克尔(3 次,再次好吧) - 但然后为每个迈克尔的出现找到它自己的大卫(但是这是相同的大卫,对于相同的迈克尔!) - 然后对于每个大卫都找到了它自己的马克(对于相同的马克 - 相同的大卫)。
我的目标只是找到从 Mike 开始的完整层次结构,即找到从 Mike 按 REFERENCE = PROPERTY 行走可以到达的所有元素。所以,我想要的结果集如下所示:
姓名 |
---|
迈克 |
詹姆斯 |
约翰 |
罗伯特 |
迈克尔 |
大卫 |
马克 |
我知道通过添加“DISTINCT”我可以实现我的目标:
...
SELECT DISTINCT NAME FROM rec;
但重点是,无论如何都会找到额外的记录(过多的 Davids 和 Marks ) - 但只会从结果中丢弃。这对我来说很糟糕,因为我的真实表格比示例复杂得多,并且额外的搜索需要花费大量时间。 那么,有没有办法对数据库说——“如果你找到迈克尔 3 次——不要搜索他的参考文献 3 次——只搜索一次”。
提前致谢:)
附注首先我想到的是做类似的事情:
WITH rec as
(
...
UNION ALL
SELECT DISTINCT N_2.PROPERTY, N_2.NAME, N_2.REFERENCE
FROM NAMES N_2
JOIN rec r ON T_2.PROPERTY = r.REFERENCE
)
SELECT NAME FROM rec;
但是 Oracle 不喜欢它。
一种方法可能是找到
DISTINCT
和property
的reference
对,然后生成层次结构并将JOIN
返回到NAMES
表以获取名称:
WITH relationships (property, reference) AS (
SELECT DISTINCT property, reference
FROM names
),
hierarchy (property) AS (
SELECT property
FROM relationships
START WITH property = 0
CONNECT BY PRIOR reference = property
)
SELECT n.name
FROM hierarchy h
INNER JOIN names n
ON (h.property = n.property)
或
WITH relationships (property, reference) AS (
SELECT DISTINCT property, reference
FROM names
),
hierarchy (property, reference) AS (
SELECT property, reference
FROM relationships
WHERE property = 0
UNION ALL
SELECT r.property, r.reference
FROM hierarchy h
INNER JOIN relationships r
ON h.reference = r.property
)
SELECT n.name
FROM hierarchy h
INNER JOIN names n
ON (h.property = n.property)
哪个输出:
姓名 |
---|
迈克 |
约翰 |
詹姆斯 |
罗伯特 |
迈克尔 |
大卫 |
马克 |