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
干杯!!
假设我有两行,我想将它们都展开,以便为范围内的每个整数得到一行。例如,拿这个 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 是如何工作的。
此致,斯图阿什顿
我有 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
干杯!!
假设我有两行,我想将它们都展开,以便为范围内的每个整数得到一行。例如,拿这个 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 是如何工作的。
此致,斯图阿什顿