一张表真的非常困难的递归SQL查询

时间:2018-07-09 19:01:30

标签: sql hierarchical-data recursive-query

我想在表中找到链。 表X由3列组成

column1, column2, column3
wolf,     eat,     cat
cat,      eat,     mouse

我查询以查找“链”

SELECT t1.column1, t2.column3
FROM X AS t1
JOIN X AS t2
ON t1.column3 = t2.column1

我在这里有一条链子

wolf,     eat,     cat,    cat,      eat,     mouse

然后我可以显示

wolf, mouse

但是对下一个数据的查询是什么?

column1, column2, column3
human,   eat,    bear
bear,    eat,    wolf
wolf,    eat,    cat
cat,     eat,    mouse

我想从列1中的任意生物开始,并在列3中找到链的末端,以检查X是否吃掉Y。

测试:

Show human->wolf
Show human->mouse
Show bear->mouse

我不知道如何在此处查找进行递归查询的步骤数。

2 个答案:

答案 0 :(得分:0)

第二列与您的问题并不真正相关,因此可以归结为“标准”递归公用表表达式,其中“子”引用“父”行。

以下是标准ANSI SQL,您可能需要将其调整为实际使用的DBMS。

with recursive food_chain as (
  select col1, col3, col1||' '||col2||' '||col3 as chain
  from x
  where col1 = 'human'
  union all
  select c.col1, c.col3, p.chain||', '||c.col1||' '||c.col2||' '||c.col3
  from x as c
   join food_chain p on c.col1 = p.col3
)
select *
from food_chain;

这将导致例如:

col1  | col3  | chain                                                     
------+-------+-----------------------------------------------------------
human | bear  | human eat bear                                            
bear  | wolf  | human eat bear, bear eat wolf                             
wolf  | cat   | human eat bear, bear eat wolf, wolf eat cat               
cat   | mouse | human eat bear, bear eat wolf, wolf eat cat, cat eat mouse

由于您仅对最后一个(最终)食物链感兴趣,因此可以通过添加一个标识级别的计数器并仅选择该级别来做到这一点

with recursive food_chain as (
  select col1, col3, col1||' '||col2||' '||col3 as chain, 1 as level
  from x
  where col1 = 'human'
  union all
  select c.col1, c.col3, p.chain||', '||c.col1||' '||c.col2||' '||c.col3, p.level + 1
  from x as c
   join food_chain p on c.col1 = p.col3
)
select chain
from food_chain
order by level desc
fetch first 1 rows only

返回:

chain                                                     
----------------------------------------------------------
human eat bear, bear eat wolf, wolf eat cat, cat eat mouse

链条的起点由CTE的非递归部分中的条件定义:where col1 = 'human'

在线示例:http://rextester.com/GKTU52621

答案 1 :(得分:0)

如果您尝试在Oracle中执行此操作,则它具有很多内置功能,可以简化您的操作。

注意:我忽略了第二列eat,因为它在这里是常量。

With hunt(predator, prey) as(
  select  'human', 'bear' from dual union
  select  'bear', 'wolf' from dual union
  select  'wolf', 'cat' from dual union
  select  'cat', 'mouse' from dual
)

 select distinct * from (
 SELECT connect_by_root predator as predator, prey
 FROM   hunt connect by predator = prior prey)
 order by predator;

您的结果将如下所示:

enter image description here