Oracle Connect By 似乎产生了太多行
Oracle Connect By seems to produce too many rows
Oracle Database 12c 企业版 12.1.0.2.0 版
我想我只是遗漏了一些东西,但是如果我 运行 这个查询没有 "connect by",我会得到 2 行。当我添加 "connect by level <= 4" 时,我希望得到这 2 行中的每一行 4 次。实际结果不同
任何人都可以帮助我了解这里发生的事情吗?我不是在寻找一种只将每一行重复 4 次的解决方案——我已经找到了。我只是想了解发生了什么以及为什么。
with alpha as (
select 1 as id
from dual
),
beta as (
select 1 as alpha_id,
1 as beta_no
from dual
union all
select 1 as alpha_id,
2 as beta_no
from dual
)
select a.id,
b.beta_no,
level as the_level
from alpha a
inner join beta b
on b.alpha_id = a.id
connect by level <= 4
order by a.id,
b.beta_no,
level
;
ID BETA_NO THE_LEVEL
1 1 1
1 1 2
1 1 2
1 1 3
1 1 3
1 1 3
1 1 3
1 1 4
1 1 4
1 1 4
1 1 4
1 1 4
1 1 4
1 1 4
1 1 4
1 2 1
1 2 2
1 2 2
1 2 3
1 2 3
1 2 3
1 2 3
1 2 4
1 2 4
1 2 4
1 2 4
1 2 4
1 2 4
1 2 4
1 2 4
30 rows selected
非常感谢数学家。他在下面的答案中提供的第二个 link 正是我要找的。具体来说:
1 with t as (select 1 as id from dual union all
2 select 2 from dual)
3 --
4 select id, level
5 ,prior id
6 ,sys_connect_by_path(id,'=>') as cpath
7 from t
8* connect by level <= 3
SQL> /
ID LEVEL PRIORID CPATH
---------- ---------- ---------- --------------------------------------------------
1 1 =>1
1 2 1 =>1=>1
1 3 1 =>1=>1=>1
2 3 1 =>1=>1=>2
2 2 1 =>1=>2
1 3 2 =>1=>2=>1
2 3 2 =>1=>2=>2
2 1 =>2
1 2 2 =>2=>1
1 3 1 =>2=>1=>1
2 3 1 =>2=>1=>2
2 2 2 =>2=>2
1 3 2 =>2=>2=>1
2 3 2 =>2=>2=>2
14 rows selected.
我从那个例子中很清楚,但我很难用简洁的语言表达出来。
除了 "level <= 4" 之外没有其他条件,原始 table、视图等(在本例中来自连接)的每一行都将在级别 2 生成两行,然后再生成四行第 3 级的行,第 4 级的 8 行。"Connect by" 本质上是一连串的联接,如果您没有使用 PRIOR 运算符的条件,则您正在执行交叉联接。
您可能想要添加 "and prior a.id = a.id"。这将导致 Oracle 抱怨循环(因为当 Oracle 在受 PRIOR 约束的列中看到相同的值时,它决定达到循环)。这又可以通过添加第三个条件来解决,通常是 "and prior sys_guid() is not null".
(已编辑;原始答案参考了 NOCYCLE,使用 "prior sys_guid() is not null" 方法时不需要它。)
最近在 OTN 上对此进行了讨论:https://community.oracle.com/thread/3999985
这里讨论了同样的问题:https://community.oracle.com/thread/2526535
为了说明 Mathguy 的回答,您在 CONNECT BY 子句中遗漏了一些谓词:
with alpha as (
select 1 as id
from dual
),
beta as (
select 1 as alpha_id,
1 as beta_no
from dual
union all
select 1 as alpha_id,
2 as beta_no
from dual
)
select a.id,
b.beta_no,
level as the_level
from alpha a
inner join beta b
on b.alpha_id = a.id
connect by level <= 4
AND PRIOR a.id = a.id
AND PRIOR b.beta_no = b.beta_no
AND PRIOR sys_guid() IS NOT NULL
order by a.id,
b.beta_no,
LEVEL;
ID BETA_NO THE_LEVEL
---------- ---------- ----------
1 1 1
1 1 2
1 1 3
1 1 4
1 2 1
1 2 2
1 2 3
1 2 4
另一种方法是使用递归 with 子句:
with alpha as (
select 1 as id
from dual
),
beta as (
select 1 as alpha_id,
1 as beta_no
from dual
union all
select 1 as alpha_id,
2 as beta_no
from dual
),
multiply (id, beta_no, rn) AS (SELECT a.id,
b.beta_no,
1 rn
FROM alpha a
INNER JOIN beta b
ON a.id = b.alpha_id
UNION ALL
SELECT ID,
beta_no,
rn + 1
FROM multiply
WHERE rn + 1 <= 4)
SELECT ID,
beta_no,
rn AS the_level
FROM multiply
order by id,
beta_no,
rn;
ID BETA_NO THE_LEVEL
---------- ---------- ----------
1 1 1
1 1 2
1 1 3
1 1 4
1 2 1
1 2 2
1 2 3
1 2 4
Oracle Database 12c 企业版 12.1.0.2.0 版
我想我只是遗漏了一些东西,但是如果我 运行 这个查询没有 "connect by",我会得到 2 行。当我添加 "connect by level <= 4" 时,我希望得到这 2 行中的每一行 4 次。实际结果不同
任何人都可以帮助我了解这里发生的事情吗?我不是在寻找一种只将每一行重复 4 次的解决方案——我已经找到了。我只是想了解发生了什么以及为什么。
with alpha as (
select 1 as id
from dual
),
beta as (
select 1 as alpha_id,
1 as beta_no
from dual
union all
select 1 as alpha_id,
2 as beta_no
from dual
)
select a.id,
b.beta_no,
level as the_level
from alpha a
inner join beta b
on b.alpha_id = a.id
connect by level <= 4
order by a.id,
b.beta_no,
level
;
ID BETA_NO THE_LEVEL
1 1 1 1 1 2 1 1 2 1 1 3 1 1 3 1 1 3 1 1 3 1 1 4 1 1 4 1 1 4 1 1 4 1 1 4 1 1 4 1 1 4 1 1 4 1 2 1 1 2 2 1 2 2 1 2 3 1 2 3 1 2 3 1 2 3 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4
30 rows selected
非常感谢数学家。他在下面的答案中提供的第二个 link 正是我要找的。具体来说:
1 with t as (select 1 as id from dual union all
2 select 2 from dual)
3 --
4 select id, level
5 ,prior id
6 ,sys_connect_by_path(id,'=>') as cpath
7 from t
8* connect by level <= 3
SQL> /
ID LEVEL PRIORID CPATH
---------- ---------- ---------- --------------------------------------------------
1 1 =>1
1 2 1 =>1=>1
1 3 1 =>1=>1=>1
2 3 1 =>1=>1=>2
2 2 1 =>1=>2
1 3 2 =>1=>2=>1
2 3 2 =>1=>2=>2
2 1 =>2
1 2 2 =>2=>1
1 3 1 =>2=>1=>1
2 3 1 =>2=>1=>2
2 2 2 =>2=>2
1 3 2 =>2=>2=>1
2 3 2 =>2=>2=>2
14 rows selected.
我从那个例子中很清楚,但我很难用简洁的语言表达出来。
除了 "level <= 4" 之外没有其他条件,原始 table、视图等(在本例中来自连接)的每一行都将在级别 2 生成两行,然后再生成四行第 3 级的行,第 4 级的 8 行。"Connect by" 本质上是一连串的联接,如果您没有使用 PRIOR 运算符的条件,则您正在执行交叉联接。
您可能想要添加 "and prior a.id = a.id"。这将导致 Oracle 抱怨循环(因为当 Oracle 在受 PRIOR 约束的列中看到相同的值时,它决定达到循环)。这又可以通过添加第三个条件来解决,通常是 "and prior sys_guid() is not null".
(已编辑;原始答案参考了 NOCYCLE,使用 "prior sys_guid() is not null" 方法时不需要它。)
最近在 OTN 上对此进行了讨论:https://community.oracle.com/thread/3999985
这里讨论了同样的问题:https://community.oracle.com/thread/2526535
为了说明 Mathguy 的回答,您在 CONNECT BY 子句中遗漏了一些谓词:
with alpha as (
select 1 as id
from dual
),
beta as (
select 1 as alpha_id,
1 as beta_no
from dual
union all
select 1 as alpha_id,
2 as beta_no
from dual
)
select a.id,
b.beta_no,
level as the_level
from alpha a
inner join beta b
on b.alpha_id = a.id
connect by level <= 4
AND PRIOR a.id = a.id
AND PRIOR b.beta_no = b.beta_no
AND PRIOR sys_guid() IS NOT NULL
order by a.id,
b.beta_no,
LEVEL;
ID BETA_NO THE_LEVEL
---------- ---------- ----------
1 1 1
1 1 2
1 1 3
1 1 4
1 2 1
1 2 2
1 2 3
1 2 4
另一种方法是使用递归 with 子句:
with alpha as (
select 1 as id
from dual
),
beta as (
select 1 as alpha_id,
1 as beta_no
from dual
union all
select 1 as alpha_id,
2 as beta_no
from dual
),
multiply (id, beta_no, rn) AS (SELECT a.id,
b.beta_no,
1 rn
FROM alpha a
INNER JOIN beta b
ON a.id = b.alpha_id
UNION ALL
SELECT ID,
beta_no,
rn + 1
FROM multiply
WHERE rn + 1 <= 4)
SELECT ID,
beta_no,
rn AS the_level
FROM multiply
order by id,
beta_no,
rn;
ID BETA_NO THE_LEVEL
---------- ---------- ----------
1 1 1
1 1 2
1 1 3
1 1 4
1 2 1
1 2 2
1 2 3
1 2 4