2

私は次のようなデータを持っています:

KEY1   KEY2      KEY3   LKEY1  LKEY2     LKEY3  FLAG
====== ========= ====== ====== ========= ====== =====
09/10  10000     A1234  09/10  AU000123  A1234  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が2番目の文字と同じ長さであるLKEY2X、2番目の文字と同じ長さである場合は、直接の親を返します。この場合、レコードをオプションとしてマークする必要もあります...つまり、次のようになります。

KEY1   KEY2      KEY3   OPTION  FLAG
====== ========= ====== ======= =====
09/10  AU000123  A1234  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を使用します。)

4

2 に答える 2

6

使用するだけです:

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 
(...)
于 2012-04-30T19:38:08.903 に答える
2

あなたの投稿は、「FLAG階層クエリで親行の属性を参照するにはどうすればよいですか?」という質問に要約されると思います。

思いついたSQLが正しいかわかりません。そうでない場合はお詫び申し上げます。ただし、一般的に、これが私のアプローチでした。

階層の各レベルで、すべてのキー(SYS_CONNECT_BY_PATH)をつなぎ合わせました。次に、、、を使用して、親レベルのキーに相当するものSUBSTRINSTR特定LEVELしました。SUBSTR最後に、の定義で、キーがこのインジアウトされたキーと一致する行PARENT_FLAGのを選択します。FLAGSUBSTR

設定:

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 AU000123   A1234 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%確信していませんが、あなたが私のアプローチに従うことができることを願っています。

于 2012-04-30T18:51:19.400 に答える