Sql 如何编写不添加已访问值的递归查询?
让我们假设任何给定的客户机都可以有多个框。每个框可以包含多个项目以及多个框(子框) 不幸的是,由于业务规则,可能会创建一个循环Sql 如何编写不添加已访问值的递归查询?,sql,oracle,recursive-query,Sql,Oracle,Recursive Query,让我们假设任何给定的客户机都可以有多个框。每个框可以包含多个项目以及多个框(子框) 不幸的是,由于业务规则,可能会创建一个循环 BoxA -> Item1, BoxB, BoxC BoxB -> BoxA, BoxD 如您所见,BoxA包含BoxB,而BoxB包含BoxA 我试图解决的问题是获取客户端中给定框列表的所有子框。 因此,如果我正在寻找BoxA的子框(来自上一个示例),我将得到以下内容:BoxB、BoxC、BoxA、BoxD 这就是我到目前为止所做的: WITH bo
BoxA -> Item1, BoxB, BoxC
BoxB -> BoxA, BoxD
如您所见,BoxA包含BoxB,而BoxB包含BoxA
我试图解决的问题是获取客户端中给定框列表的所有子框。因此,如果我正在寻找BoxA的子框(来自上一个示例),我将得到以下内容:BoxB、BoxC、BoxA、BoxD 这就是我到目前为止所做的:
WITH box_info AS (
-- This is typically a bit more complicated, that's why I have it in a seperate WITH clause
SELECT sub_box_id
FROM client_box
WHERE box_id = 1
),
all_sub_boxes(sub_box_id) AS (
SELECT sub_box_id
FROM box_info
WHERE sub_box_id IS NOT NULL
UNION ALL
SELECT cb.sub_box_id
FROM client_box cb, all_sub_boxes asb
WHERE cb.box_id = asb.sub_box_id AND cb.sub_box_id IS NOT NULL
-- AND cb.sub_box_id NOT IN (SELECT sub_box_id FROM all_sub_boxes)
)
SELECT sub_box_id FROM all_sub_boxes;
但是,由于有可能陷入递归循环,WITH子句的“all_sub_BOX”将失败。注释掉的行是我直观地放进去的,因为它防止已经访问过的子框被添加到递归列表中,但是我们似乎不能从内部引用“所有子框”
因此,本质上,我需要一种在递归查询中不包含已经包含的子框的方法。也许我可以创建一个临时表?但我甚至不知道在递归查询期间是否可以插入到表中。另外,如果每次都创建临时表,那么每次运行此查询的成本是多少 我正在尝试编写这个查询,以便它可以跨不同的商业数据库使用,所以如果我可以避免使用非标准sql,那就太好了。但我明白,如果不可能,那就是事实 编辑 为清晰起见,以下是
客户机\u框
表的外观:
+--------+---------+------------+
| BOX_ID | ITEM_ID | SUB_BOX_ID |
+--------+---------+------------+
| BoxA | Item1 | (null) |
| BoxA | (null) | BoxB |
| BoxA | (null) | BoxC |
| BoxB | (null) | BoxA |
| BoxB | (null) | BoxD |
+--------+---------+------------+
你在正确的轨道上,你似乎只是需要一点帮助来处理周期。请参阅递归CTE定义末尾的CYCLE子句(即使CYCLE子句位于递归CTE的右括号之后,它仍然是它的一部分):
“我在寻找BoxA的子框”推断BoxA位于层次结构树中任何“子框”的上方(父级)。所以你应该返回B,C,D子框(儿童),我想。无论如何,听起来您需要一个分层树查询(可能是nocycle)。寻找more@tbone是的,这是准确的。“连接方式”是oracle特有的关键字,对吗?有没有一种方法可以不用特定于Oracle的东西来编写这个查询?恕我直言,但我始终不理解这样一个想法,即您必须不惜一切代价争取通用的香草味SQL。我假设您的公司正在为Oracle许可证付费(基于您的问题Oracle标签),所以请使用您已经付费的工具。可能会有涉及多层连接的黑客攻击,或者复杂(可能有缺陷)的过程代码,但是如果您的数据库提供现成的解决方案,我会首先使用它。也就是说,我相信其他主要数据库支持或将支持分层查询的概念(例如)@我问这个问题的唯一原因是因为我们可能要离开甲骨文了。这就是为什么我想看看这是否可能,因为我不想经历翻译的头痛。但正如我所说的,如果不可能,那没关系,我只使用CONNECT BY子句。非常感谢您发布这篇文章。然而,我试图找到更多关于CYCLE关键字的信息,但没有任何明确的信息。我可能只是找错地方了。你能给我提供更多的信息或给我指出正确的文档吗?还有,这是Oracle特有的关键字吗?@gjvatsalya-看看这是否有用。另外,看看PostgreSQL现在是否有类似于cycle子句的内容,它似乎在八年前没有。
+--------+---------+------------+
| BOX_ID | ITEM_ID | SUB_BOX_ID |
+--------+---------+------------+
| BoxA | Item1 | (null) |
| BoxA | (null) | BoxB |
| BoxA | (null) | BoxC |
| BoxB | (null) | BoxA |
| BoxB | (null) | BoxD |
+--------+---------+------------+
with
-- Begin simulated data.
client_box ( box_id, item_id, sub_box_id ) as (
select 'BoxA', 'Item1', null from dual union all
select 'BoxA', null , 'BoxB' from dual union all
select 'BoxA', null , 'BoxC' from dual union all
select 'BoxB', null , 'BoxA' from dual union all
select 'BoxB', null , 'BoxD' from dual
),
-- End of simulated data (for testing only, not part of the solution).
-- SQL query consists of the keyword WITH (above) and the lines below.
-- Use your actual table and column names.
-- Use whatever mechanism works for you in the ANCHOR branch of r (below).
r ( box_id ) as (
select 'BoxA' from dual -- Modify this for inputs
union all
select c.sub_box_id
from client_box c join r on c.box_id = r.box_id
where c.sub_box_id is not null
)
cycle box_id set cycle to 1 default 0
select box_id
from r
where cycle = 0
;
BOX_ID
------
BoxA
BoxB
BoxC
BoxD