2013-07-10 41 views
3

我們在Oracle 11g R1上。下面的代碼:Oracle「通過連接」 - 多個層次結構

CREATE TABLE T1 (ID NUMBER, PARENT_ID NUMBER, LEFT_SIBLING_ID NUMBER); 
INSERT INTO T1 VALUES (1,NULL,NULL); 
INSERT INTO T1 VALUES (3,1,NULL); 
INSERT INTO T1 VALUES (2,1,3); 
INSERT INTO T1 VALUES (4,2,NULL); 
INSERT INTO T1 VALUES (5,2,4); 
INSERT INTO T1 VALUES (10,NULL,1); 
INSERT INTO T1 VALUES (12,10,NULL); 
INSERT INTO T1 VALUES (11,10,12); 

我想結果是什麼要的是:

ID-Tree 
1 
    3 
    2 
     4 
     5 
10 
    12 
    11 

這裏的關鍵是,除了常用的PRIOR ID = PARENT_ID層次,有基於以前的ID另一層次= LEFT_SIBLING_ID。孩子們按照PRIOR ID = LEFT_SIBLING_ID的順序排序。這就是爲什麼3跟着是2,而12是11等。這個順序很重要。

我在如何做到這一點上畫了一個空白。

編輯:

更多行清楚地說明排序問題:

CREATE TABLE T1 (ID NUMBER, PARENT_ID NUMBER, LEFT_SIBLING_ID NUMBER); 
INSERT INTO T1 VALUES (1,NULL,10); 
INSERT INTO T1 VALUES (3,1,NULL); 
INSERT INTO T1 VALUES (2,1,3); 
INSERT INTO T1 VALUES (4,2,NULL); 
INSERT INTO T1 VALUES (5,2,4); 
INSERT INTO T1 VALUES (10,NULL,NULL); 
INSERT INTO T1 VALUES (12,10,NULL); 
INSERT INTO T1 VALUES (7,10,12); 
INSERT INTO T1 VALUES (11,10,7); 
INSERT INTO T1 VALUES (6,1,2); 
INSERT INTO T1 VALUES (13,1,6); 
COMMIT; 

查詢結果:

select substr('----------', 1, lvl*2-2) || to_char(id) id_tree 
from 
(select SYS_CONNECT_BY_PATH(to_char(id,'009'), ':') sort_path, 
     left_sibling_id, id, parent_id, level lvl 
from t1 
start with parent_id is null 
connect by prior id = parent_id) q 
start with left_sibling_id is null 
connect by prior id = left_sibling_id 
and coalesce(parent_id,id) = coalesce(parent_id,id) 
order by case lvl when 1 then sort_path 
        else substr(sort_path,1,length(sort_path)-4) end, 
     level; 

ID_TREE            
-------------------------------------------------- 
1             
--3             
--2             
--6             
--13            
----4            
----5            
10             
--12            
--7             
--11            

11 rows selected 

雖然兄弟姐妹都正常有序的(除了頂層),他們不再立即在他們的父母之下。

+0

有其他的方式來訂購的兄弟姐妹。你必須專門使用這個嗎? –

+0

您可以使用「sort_order」列,然後使用「ORDER SIBLINGS BY sort_order」而不是對「左兄弟」的引用。 –

+0

我無法更改表格,所以我必須專門使用這個表格。之所以選擇這種方式,是因爲它被認爲可以加速新ID的加入。在此實現中,只需要一個插入(新ID)和一個更新(更改一個現有記錄的LEFT_SIBLING_ID)。如果有「sort_order」列,則新列之後的所有兄弟將需要更新其「sort_order」列。至少這是那個想法。 – SKY

回答

1

終於!

我通過在LEFT_SIBLING_ID上執行CONNECT BY創建了一個名爲SIBLING_LEVEL的「排序順序」列。然後我將它加入原始表格。然後在那個加入的結果做了一個簡單的連接按順序排列。對我來說似乎有點蠻橫,但這是我所能想到的。

SELECT ROWNUM, LPAD(' ', (LEVEL*2) - 1, '-') || ID AS HIERARCHY, PARENT_ID, 
LEFT_SIBLING_ID, LEVEL AS PARENT_CHILD_LEVEL 
from 
(
SELECT A.ID, A.PARENT_ID, A.LEFT_SIBLING_ID, B.SIBLING_LEVEL 
FROM 
T1 A 
, 
(
SELECT ID, SUBSTR('----------', 1, LVL*2-2) || TO_CHAR(ID) ID_TREE, 
LEVEL AS SIBLING_LEVEL 
FROM 
(SELECT SYS_CONNECT_BY_PATH(TO_CHAR(ID,'009'), ':') SORT_PATH, 
    LEFT_SIBLING_ID, ID, PARENT_ID, LEVEL LVL 
FROM T1 
START WITH PARENT_ID IS NULL 
CONNECT BY PRIOR ID = PARENT_ID) Q 
START WITH LEFT_SIBLING_ID IS NULL 
CONNECT BY PRIOR ID = LEFT_SIBLING_ID) B 
WHERE A.ID = B.ID 
) C 
START WITH C.PARENT_ID IS NULL 
CONNECT BY PRIOR C.ID = C.PARENT_ID 
ORDER SIBLINGS BY SIBLING_LEVEL; 

http://sqlfiddle.com/#!4/fcd68/5/0