2016-03-15 25 views
2

这个SELECT语句带来奇怪的结果:事先连接带来意想不到的效果

with data(id, seqno, cs_prev_seqno, descr) as 
(select 1, 1, 0, 'Id 1 Step1' from dual 
    union all 
    select 1, 2, 1, 'Id 1 Step2' from dual 
    union all 
    select 1, 3, 2, 'Id 1 Step3' from dual 
    union all 
    select 1, 4, 1, 'Id 1 Step4' from dual  
    union all 
    select 2, 1, 0, 'Id 2 Step1' from dual 
    union all 
    select 2, 2, 1, 'Id 2 Step2' from dual) 

select id, 
     sys_connect_by_path(seqno, '/') as path, 
     seqno, 
     cs_prev_seqno, 
     descr, 
     level 
    from data 
where id = 1 
connect by prior seqno = cs_prev_seqno 
start with cs_prev_seqno = 0; 

我预计connect by只是为了与ID = 1的行完成的,但结果是:

id path seq seq_prev descr  level 
1 /1  1 0  Id 1 Step1 1 
1 /1/2 2 1  Id 1 Step2 2 
1 /1/2/3 3 2  Id 1 Step3 3 
1 /1/2/3 3 2  Id 1 Step3 3 
1 /1/4 4 1  Id 1 Step4 2 
1 /1/2 2 1  Id 1 Step2 2 
1 /1/2/3 3 2  Id 1 Step3 3 
1 /1/2/3 3 2  Id 1 Step3 3 
1 /1/4 4 1  Id 1 Step4 2 

IE首先是connect by是所有行完成的,后来的结果是由ID过滤。

作为一种解决方法,下面的语句提供了正确的结果:

with data(id, 
seqno, 
cs_prev_seqno, 
descr) as 
(select 1, 1, 0, 'Id 1 Step1' 
    from dual 
    union all 
    select 1, 2, 1, 'Id 1 Step2' 
    from dual 
    union all 
    select 1, 3, 2, 'Id 1 Step3' 
    from dual 
    union all 
    select 1, 4, 1, 'Id 1 Step4' 
    from dual 

    union all 
    select 2, 1, 0, 'Id 2 Step1' 
    from dual 
    union all 
    select 2, 2, 1, 'Id 2 Step2' 
    from dual 

) 

, 
data2 as 
(select d.id, 
     d.seqno, 
     d.cs_prev_seqno, 
     d.id || '.' || d.seqno as id_seqno, 
     d.id || '.' || d.cs_prev_seqno as cs_id_prev_seqno, 
     d.descr 
    from data d) 

select id, 
     sys_connect_by_path(seqno, '/') as path, 
     seqno, 
     cs_prev_seqno, 
     descr, 
     level 
    from data2 
where id = 1 
connect by prior id_seqno = cs_id_prev_seqno 
start with cs_prev_seqno = 0; 

- >

id path seq seq_prev descr  level 
1 /1  1 0  Id 1 Step1 1 
1 /1/2 2 1  Id 1 Step2 2 
1 /1/2/3 3 2  Id 1 Step3 3 
1 /1/4 4 1  Id 1 Step4 2 

但我想应该有实现这个更简单的方法?提前致谢!

回答

2

使用CONNECT BY到限制连接到相同的地址ID

CONNECT BY PRIOR id = id 
     AND PRIOR seqno = cs_id_prev_seqno 

这将使您的查询:

SELECT  id, 
      SYS_CONNECT_BY_PATH(seqno, '/') AS path, 
      seqno, 
      cs_prev_seqno, 
      descr, 
      level 
FROM  data d 
WHERE  id = 1 
CONNECT BY PRIOR id = id 
     AND PRIOR seqno = cs_id_prev_seqno 
START WITH cs_prev_seqno = 0; 

我预计connect by只是为了与ID = 1

行做当你发现了,这是不正确的。查询将找到所有行,其中:

  • 根行有cs_prev_seqno = 0(根据START WITH子句);
  • 当前行具有id = 1(所述WHERE条款);和
  • 也就是说,在每一步,从根到当前行的CONNECT BY子句是满意的。

如果CONNECT BY子句没有指定ID应该是常量,那么在这些干预步骤中将不会检查它。

1

如果我没有理解好了,你可以尝试限制数据集应用CONNECT BY之前,例如:

with data(id, seqno, cs_prev_seqno, descr) as 
(select 1, 1, 0, 'Id 1 Step1' from dual union all 
    select 1, 2, 1, 'Id 1 Step2' from dual union all 
    select 1, 3, 2, 'Id 1 Step3' from dual union all 
    select 1, 4, 1, 'Id 1 Step4' from dual union all 
    select 2, 1, 0, 'Id 2 Step1' from dual union all 
    select 2, 2, 1, 'Id 2 Step2' from dual) 
select id, 
     sys_connect_by_path(seqno, '/') as path, 
     seqno, 
     cs_prev_seqno, 
     descr, 
     level 
    from (select * from data where id = 1) 
connect by prior seqno = cs_prev_seqno 
start with cs_prev_seqno = 0; 

你甚至可以使用你的条件CONNECT BY子句中:

with data(id, seqno, cs_prev_seqno, descr) as 
(select 1, 1, 0, 'Id 1 Step1' from dual union all 
    select 1, 2, 1, 'Id 1 Step2' from dual union all 
    select 1, 3, 2, 'Id 1 Step3' from dual union all 
    select 1, 4, 1, 'Id 1 Step4' from dual union all 
    select 2, 1, 0, 'Id 2 Step1' from dual union all 
    select 2, 2, 1, 'Id 2 Step2' from dual) 
select id, 
     sys_connect_by_path(seqno, '/') as path, 
     seqno, 
     cs_prev_seqno, 
     descr, 
     level 
from data where id = 1 
connect by prior seqno = cs_prev_seqno 
     and prior id = 1 
start with cs_prev_seqno = 0; 
相关问题