2016-11-04 68 views
0

在過去的幾天裏,我正在爲我的任務開發解決方案,而我似乎無法找到答案。Oracle SQL connect_by_root和子查詢

介紹:假設我們有一張叫的人。每個人有三個字段:name,bosspositionname是主鍵,position只是一個字符串,boss作爲外鍵指向不同的人的name。它創建了一個像Person1 - > Person2 - > Person3 - > Person4這樣的普通樹,其中Person4是最高級的boss,Person1是root。爲簡單起見讓我們假設沒有人具有多於3個老闆,Person4是頭老闆

實施例的路徑(的唯一的人與boss等於null):

Person7 - > Person4

Person6 - > Person8 - > Person4

PERSON2 - > Person8 - > Person4

所以我的任務說:創建一個顯示在分層ORD查詢呃,每個老闆的每個人的名字position等於「工人」,或只使用樹操作(通過連接,CONNECT_BY_ROOT等)「經理」 和子

輸出表必須由5列:

Name | Position | Boss 1 | Boss 2 | Boss 3 

如果任何boss列將爲空,那麼我應該插入一些空格。

這是我的查詢到目前爲止:

select 
    case  
    when l = 1 then name else ' ' end as "Name", 
    position, 
    case 
    when l = 2 then name else ' ' end as "Boss 1", 
    case 
    when l = 3 then name else ' ' end as "Boss 2", 
    case 
    when l = 4 then name else ' ' end as "Boss 3"  
from (
    select 
    connect_by_root position as position, 
    level as l, 
    name 
    from 
    People 
    connect by prior 
    boss = name 
    start with 
    position = 'Worker' 
    or position = 'Manager' 
); 

它有點做的伎倆,但樹的每個級別是一個新行,這件事情我必須避免。我知道爲什麼這個查詢產生這樣的結果,但我不知道如何使它遍歷樹而不在每一步創建新行。

我的結果:

Name |Position|Boss 1|Boss 2|Boss 3 

JOHN WORKER     
     WORKER HENRY    
     WORKER   PETER  
TERRY WORKER      
     WORKER PETER    
ALICE WORKER     
     WORKER PETER    
BILL MANAGER      
     MANAGER JAMES    
     MANAGER   PETER  

這是結果我想要實現:

Name |Position|Boss 1|Boss 2|Boss 3 

JOHN WORKER HENRY PETER   

TERRY WORKER PETER     

ALICE WORKER PETER     

BILL MANAGER JAMES PETER     

請問有什麼解決,而無需使用複雜的功能,如透視,使其工作

+0

只是'max'或'min'功能。並且用'... name else'結尾...'替換'... name else''end ...' – Dmitry

+0

這些函數放入子查詢中? – Karatte

回答

0

它應該是這樣的(我沒有源數據,以檢查):

select 
    root_name as "Name", 
    max(position), 
    max(case when l = 2 then name else null end) as "Boss 1", 
    max(case when l = 3 then name else null end) as "Boss 2", 
    max(case when l = 4 then name else null end) as "Boss 3"  
from (
    select 
    connect_by_root position as position, 
    connect_by_root name as root_name, 
    level as l, 
    name 
    from 
    People 
    connect by prior 
    boss = name 
    start with 
    position = 'Worker' 
    or position = 'Manager' 
) 
group by root_name; 
+0

你錯過了group by子句,再加上這是一種pivoting的形式,我不認爲OP是特別想做的。 – Boneist

+1

@骨頭人哦,謝謝!我試圖在原始查詢中做出最小的更正。 – Dmitry

+0

工程就像一個魅力,現在我需要考慮解決方案。這裏有'max'函數可以做什麼?這只是一種解決方法,能夠'root by'root_name?它是否像「從null和name中選擇max」這樣的東西總是返回名稱? – Karatte

0

有可能做到這一點而不需要任何樞軸等,僅通過使用CONNECT_BY_ROOTCONNECT_BY_ISLEAFSYS_CONNECT_BY_PATH,加上明智地使用REGEXP_SUBSTR

WITH people AS (SELECT 'JOHN' name, 'WORKER' position, 'HENRY' boss FROM dual UNION ALL 
       SELECT 'HENRY' name, 'CFO' position, 'PETER' boss FROM dual UNION ALL 
       SELECT 'TERRY' name, 'WORKER' position, 'PETER' boss FROM dual UNION ALL 
       SELECT 'ALICE' name, 'WORKER' position, 'PETER' boss FROM dual UNION ALL 
       SELECT 'JAMES' name, 'CIO' position, 'PETER' boss FROM dual UNION ALL 
       SELECT 'FRED' name, 'MANAGER' position, NULL boss FROM dual UNION ALL 
       SELECT 'BILL' name, 'MANAGER' position, 'JAMES' boss FROM dual UNION ALL 
       SELECT 'PETER' name, 'CEO' position, 'FRED' boss FROM dual) 
-- end of mimicking your people table with some sample data in it 
-- you wouldn't need the above, just use the query below: 
SELECT connect_by_root name AS name, 
     connect_by_root position AS position, 
     regexp_substr(sys_connect_by_path(boss, '>'), '[^>]+', 1, 1) boss1, 
     regexp_substr(sys_connect_by_path(boss, '>'), '[^>]+', 1, 2) boss2, 
     regexp_substr(sys_connect_by_path(boss, '>'), '[^>]+', 1, 3) boss3 
FROM people 
WHERE connect_by_isleaf = 1 
CONNECT BY PRIOR boss = name 
START WITH position IN ('WORKER', 'MANAGER'); 

NAME POSITION BOSS1 BOSS2 BOSS3 
----- -------- ----- ----- ----- 
ALICE WORKER PETER FRED 
BILL MANAGER JAMES PETER FRED 
FRED MANAGER    
JOHN WORKER HENRY PETER FRED 
TERRY WORKER PETER FRED 

CONNECT_BY_ISLEAF確定該行是否是一個葉行(1)或不是(0)。因此,就像您可以使用CONNECT_BY_ROOT來標識根值一樣,您可以通過使用CONNECT_BY_ISLEAF來確定哪一行是最後一行。

SYS_CONNECT_BY_PATH生成到目前爲止所有值的路徑。所以,在葉子行上,它將包含所有必要的值。然後我們可以解析這個生成的字符串以獲取不包含路徑分隔符的第一個,第二個等部分。