2012-04-30 28 views
0

我有看起來像這樣的數據:參考在Oracle CONNECT父列BY分層查詢

KEY1 KEY2  KEY3 LKEY1 LKEY2  LKEY3 FLAG 
====== ========= ====== ====== ========= ====== ===== 
09/10 10000  A1234 09/10 AU00A1234 1 
09/10 10000  A1234 09/10 AU000456 A1234 1 
09/10 10000  A1234 09/10 AX000001 A1234 1 
09/10 AX000001 A1234 09/10 AE000010 A1234 0 
09/10 AX000001 A1234 09/10 AE000020 A1234 0 
09/10 AX000001 A1234 09/10 AE000030 A1234 0 
09/10 10000  A1234 09/10 AX000002 A1234 0 
09/10 AX000002 A1234 09/10 AE000040 A1234 0 
09/10 10000  A1234 09/10 AU000789 A1234 0 

這是分層數據,由此我將查詢針對根複合鍵(在這種情況下09/10 10000 A1234); FLAG字段指的是由LKEYx密鑰標識的「對象」。可以有任何級別的嵌套。 (請注意,KEY1KEY3領域不必是不變的,如上面的例子,只要層次結構將被保留。)

我想檢索哪些葉節點,如果一片樹葉的父KEY2是相同的長度或LKEY2含有X作爲第二字符,則返回的直接父。在這種情況下,我們還需要標註記錄作爲可選的...所以,這樣的事情:

KEY1 KEY2  KEY3 OPTION FLAG 
====== ========= ====== ======= ===== 
09/10 AU00A1234 0  1 
09/10 AU000456 A1234 0  1 
09/10 AX000001 A1234 1  1 
09/10 AX000002 A1234 1  0 
09/10 AU000789 A1234 0  0 

我寫了一個查詢,這樣做,但它不是漂亮。此外,它假定所有葉節點都在樹下的同一級別,以便區分可選記錄;但是,這不一定是真的。我的查詢如下:

with queryKeys as (
    select '09/10' key1, 
     '10000' key2, 
     'A1234' key3, 
    from dual 
), 
subTree as (
    select  tree.key1, 
      tree.key2, 
      tree.key3, 

      tree.lkey1, 
      tree.lkey2, 
      tree.lkey3, 

      tree.flag, 

      connect_by_isleaf isLeaf, 
      level thisLevel 

    from  tree, 
      queryKeys 

    start with tree.key1 = queryKeys.key1 
    and  tree.key2 = queryKeys.key2 
    and  tree.key3 = queryKeys.key3 

    connect by tree.key1 = prior tree.lkey1 
    and  tree.key2 = prior tree.lkey2 
    and  tree.key3 = prior tree.lkey3 
), 
maxTree as (
    select max(thisLevel) maxLevel 
    from subTree 
) 
select lkey1 key1, 
     lkey2 key2, 
     lkey3 key3, 
     1 - isLeaf option, 
     flag 

from subTree, 
     maxTree 
where (isLeaf = 1 or thisLevel = maxLevel - 1) 
and (length(key2) != length(lkey2) or substr(lkey2, 2, 1) != 'X'); 

原因queryKeys是因爲它是在一個大的查詢在其他地方使用,並且可以包含多個記錄。 maxTree部分是問題,超出它的一般怪癖!現在

,該文章的標題的原因是因爲這種查詢可以作出很多更直接,如果我能指的是父母的FLAG場。我嘗試了JOIN對待這一想法 - 用自己的相關按鍵加入了樹 - 但是,除非我錯了,這將導致遞歸問題,你會保持不必重複了樹查找正確的父鍵(因爲KEYxLKEYx字段都定義了記錄的完整組合鍵)。

(PS使用Oracle 10gR2中,如果它的確與衆不同。)

回答

3

只需使用:

PRIOR FLAG 

它會給你你想要什麼 - 父行的標誌字段。

subTree as (   
select  tree.key1,    
     tree.key2,    
     tree.key3,    
     tree.lkey1,    
     tree.lkey2,    
     tree.lkey3,    
     tree.flag,    
     PRIOR TREE.FLAG PRIOR_FLAG 
     connect_by_isleaf isLeaf,    
     level thisLevel    

from  tree,    
     queryKeys 
(...) 
+0

美麗!謝謝 :) – Xophmeister

1

我認爲您的文章可以歸結爲一個問題:「我如何引用父行的FLAG屬性的分層查詢? 「

我不知道SQL我已經想出是正確的。如果不是,我很抱歉。在一般情況下,雖然,這裏是我的方法:

在層次結構中的每一個層面,我絲絃了所有的按鍵(SYS_CONNECT_BY_PATH)。然後使用SUBSTRINSTRLEVEL,我SUBSTR inged了什麼相當於父級重點。最後,在PARENT_FLAG定義,我選擇一行,其關鍵這SUBSTR inged出密鑰匹配的FLAG

設置:

CREATE TABLE tree (
    key1  VARCHAR2(5) 
, key2  VARCHAR2(10) 
, key3  VARCHAR2(5) 
, lkey1  VARCHAR2(5) 
, lkey2  VARCHAR2(10) 
, lkey3  VARCHAR2(5) 
, flag  VARCHAR2(1) 
); 
INSERT INTO tree VALUES ('09/10','10000','A1234','09/10','AU000123','A1234','1'); 
INSERT INTO tree VALUES ('09/10','10000','A1234','09/10','AU000456','A1234','1'); 
INSERT INTO tree VALUES ('09/10','10000','A1234','09/10','AX000001','A1234','1'); 
INSERT INTO tree VALUES ('09/10','AX000001','A1234','09/10','AE000010','A1234','0'); 
INSERT INTO tree VALUES ('09/10','AX000001','A1234','09/10','AE000020','A1234','0'); 
INSERT INTO tree VALUES ('09/10','AX000001','A1234','09/10','AE000030','A1234','0'); 
INSERT INTO tree VALUES ('09/10','10000','A1234','09/10','AX000002','A1234','0'); 
INSERT INTO tree VALUES ('09/10','AX000002','A1234','09/10','AE000040','A1234','0'); 
INSERT INTO tree VALUES ('09/10','10000','A1234','09/10','AU000789','A1234','0'); 

查詢:

COL flag   FOR A4 
COL same_length FOR A11 
COL has_x_2nd  FOR A9 
COL full_key_path FOR A50 
COL parent_key FOR A30 
COL parent_flag FOR A11 
WITH querykeys AS (
    SELECT '09/10' key1 
    ,  '10000' key2 
    ,  'A1234' key3 
    FROM DUAL 
) 
, subtree1 AS (
    SELECT  tree.key1 
    ,   tree.key2 
    ,   tree.key3 
    ,   tree.lkey1 
    ,   tree.lkey2 
    ,   tree.lkey3 
    ,   tree.flag 
    ,   CONNECT_BY_ISLEAF isleaf 
    ,   LEVEL thislevel 
    ,   DECODE(LENGTH(tree.key2) 
      ,  LENGTH(tree.lkey2), '1' 
      ,  '0') same_length 
    ,   DECODE(UPPER(SUBSTR(tree.key2,2,1)) 
      ,  'X', '1' 
      ,  '0') has_x_2nd 
    ,   SYS_CONNECT_BY_PATH(tree.key1 || '|' || tree.key2 || '|' || tree.key3,'\') 
      || '\' 
      || tree.lkey1 || '|' || tree.lkey2 || '|' || tree.lkey3 || '\' full_key_path 
    FROM  tree 
    ,   querykeys 
    START WITH tree.key1 = querykeys.key1 
    AND  tree.key2 = querykeys.key2 
    AND  tree.key3 = querykeys.key3 
    CONNECT BY tree.key1 = PRIOR tree.lkey1 
    AND  tree.key2 = PRIOR tree.lkey2 
    AND  tree.key3 = PRIOR tree.lkey3 
) 
, subtree2 AS (
    SELECT st1.key1 
    ,  st1.key2 
    ,  st1.key3 
    ,  st1.lkey1 
    ,  st1.lkey2 
    ,  st1.lkey3 
    ,  st1.flag 
    ,  st1.isleaf 
    ,  st1.thislevel 
    ,  st1.same_length 
    ,  st1.has_x_2nd 
    ,  st1.full_key_path 
    ,  SUBSTR(st1.full_key_path 
      ,  INSTR(st1.full_key_path,'\',1,st1.thislevel) + 1 
      ,  INSTR(st1.full_key_path,'\',1,st1.thislevel + 1) 
        - INSTR(st1.full_key_path,'\',1,st1.thislevel) - 1) parent_key 
    FROM subtree1 st1 
) 
SELECT st2.key1 
,  st2.key2 
,  st2.key3 
,  st2.lkey1 
,  st2.lkey2 
,  st2.lkey3 
,  st2.flag 
,  st2.isleaf 
,  st2.thislevel 
,  st2.same_length 
,  st2.has_x_2nd 
,  (SELECT t_prime.flag 
     FROM tree t_prime 
     WHERE t_prime.key1 = SUBSTR(st2.parent_key 
           ,  1 
           ,  INSTR(st2.parent_key,'|',1,1) - 1) 
     AND t_prime.key2 = SUBSTR(st2.parent_key 
           ,  INSTR(st2.parent_key,'|',1,1) + 1 
           ,  INSTR(st2.parent_key,'|',1,2) 
            - INSTR(st2.parent_key,'|',1,1) - 1) 
     AND t_prime.key3 = SUBSTR(st2.parent_key 
           ,  INSTR(st2.parent_key,'|',1,2) + 1) 
     -- Following assumes all rows with parent keys have same flag value. 
     -- Avoids ORA-01427: single-row subquery returns more than one row. 
     AND ROWNUM = 1) parent_flag 
FROM subtree2 st2 
; 

結果:

KEY1 KEY2  KEY3 LKEY1 LKEY2  LKEY3 FLAG  ISLEAF THISLEVEL SAME_LENGTH HAS_X_2ND PARENT_FLAG 
----- ---------- ----- ----- ---------- ----- ---- ---------- ---------- ----------- --------- ----------- 
09/10 10000  A1234 09/10 AU00A1234 1    1   1 0   0   1 
09/10 10000  A1234 09/10 AU000456 A1234 1    1   1 0   0   1 
09/10 10000  A1234 09/10 AU000789 A1234 0    1   1 0   0   1 
09/10 10000  A1234 09/10 AX000001 A1234 1    0   1 0   0   1 
09/10 AX000001 A1234 09/10 AE000010 A1234 0    1   2 1   1   0 
09/10 AX000001 A1234 09/10 AE000020 A1234 0    1   2 1   1   0 
09/10 AX000001 A1234 09/10 AE000030 A1234 0    1   2 1   1   0 
09/10 10000  A1234 09/10 AX000002 A1234 0    0   1 0   0   1 
09/10 AX000002 A1234 09/10 AE000040 A1234 0    1   2 1   1   0 

9 rows selected. 

SQL> 

正如我所說,我不是100%肯定,我完全grokked你的數據模型,但我希望你能夠遵循我的方法。

+0

我選擇了@ arturro的答案,因爲它解析路徑的簡單性,但爲你的努力+ 1。謝謝:) – Xophmeister