2016-03-15 50 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; 
相關問題