oracle 中 sql 输出流的混乱

Confusion in flow of sql output in oracle

我有 table T 作为:

所以,我从某处得到 sql 作为:

select * from (
SELECT start_range,(LEVEL + START_RANGE)-1 NUM,end_range
   FROM offc.T
  CONNECT BY (LEVEL +START_RANGE ) <= END_RANGE+1) order by start_range,num,end_range;

我得到的输出为:

我正在描述这个查询 运行 现在如何:

第一层=1 所以, start_range=1 和 end_range=3 循环到 1 到 3; 所以,输出是:

start_range | num | end_range
   1          1       3       2<=4,level=1
   1           2       3      3<=4,level=2
   1           3       3      4<=4,level=3
and the new start_range=5 and end_range=5.

但是,我越来越困惑这个循环是怎么回事了?我没有看到很多 具有 1 2 3 数据的行:

这 1 2 3 行怎么不止一次出现了?谁能帮我理解这个sql的流程?

通过查询连接并不像您想象的那样有效。

当每一行的循环条件不同时,其结果相乘

您可以使用以下查询来获得所需的结果:

with t (start_range, end_range) as
(select 1,3 from dual union all
select 5,5 from dual union all
select 7,9 from dual)
select start_range, end_range, start_range+a.column_value as num
from t, table(cast(multiset(
                 select level-1 from dual
                 connect by level <= end_range - start_range + 1 ) 
           as sys.odciNumberList)) a

db<>fiddle demo

干杯!!

假设我有两行,我想将它们都展开,以便为范围内的每个整数得到一行。例如,拿这个 table:

drop table U purge;

create table U as
select 1 range_id, 2 range_end from dual
union all
select 2, 3 from dual;

select * from u;
ID  END
1   2
2   3

如果我尝试像你这样的尝试:

select range_id, range_end, level
from u
connect by level <= range_end;

ID  END  LEVEL
1   2   1
1   2   2
2   3   3
2   3   2
2   3   3
2   3   1
1   2   2
2   3   3
2   3   2
2   3   3

这是什么乱七八糟的东西?看起来我从每一行开始并连接到另一行 – 这是有道理的,因为我并不是说要留在同一行 。我们再试一次:

select range_id, range_end, level
from u
connect by level <= range_end
and range_id = prior range_id

Error report - SQL Error: ORA-01436: CONNECT BY loop in user data

现在我参考了之前的东西——range_id。 Oracle 看到相同的 range_id 被连续两次访问,因此它假定存在无限循环并中止执行。

有一种方法可以避免该错误,使用 NOCYCLE 关键字:

select range_id, range_end, level
from u
connect by nocycle level <= range_end
and range_id = prior range_id;

ID  END LEVEL
1   2   1
2   3   1

嗯,我没有报错,但是Oracle还是认为同样的range_id做两次会是一个循环,所以它先停止了。

我们需要在前面的行中添加一些内容,让 Oracle 认为它是不同的。 SYS_GUID() 是一个成本非常低的函数,returns 是一个非重复值。如果我们在条件中引用 PRIOR SYS-GUID(),这足以使前一行唯一并防止出现无限循环。

select range_id, range_end, level
from u
connect by level <= range_end
and range_id = prior range_id
and prior sys_guid() is not null;

ID  END LEVEL
1   2   1
1   2   2
2   3   1
2   3   2
2   3   3

将此技术应用于您的数据:

with data(start_range, end_range) as (
select 1, 3 from dual
union all select 5, 7 from dual
)
SELECT start_range, end_range,
  start_range + level - 1 num
FROM data
CONNECT BY start_range + level - 1 <= END_RANGE
and start_range = prior start_range
and prior sys_guid() is not null;

另一个答案也有效!我只是想解释一下 CONNECT BY 是如何工作的。

此致,斯图阿什顿