2009-06-10 18 views
2

一部の列が前の一致する行から構築されるようなクエリを作成しようとしています。たとえば、次のデータがあります。Oracle SQLクエリ(Analytics?)

CREATE TABLE TEST (SEQ NUMBER, LVL NUMBER, DESCR VARCHAR2(10)); 
INSERT INTO TEST VALUES (1, 1, 'ONE'); 
INSERT INTO TEST VALUES (2, 2, 'TWO1'); 
INSERT INTO TEST VALUES (3, 2, 'TWO2'); 
INSERT INTO TEST VALUES (4, 3, 'THREE1'); 
INSERT INTO TEST VALUES (5, 2, 'TWO3'); 
INSERT INTO TEST VALUES (6, 3, 'THREE2'); 
COMMIT 

次のデータを取得します。

SEQ L1 L2 L3 
1 ONE NULL NULL 
2 ONE TWO1 NULL 
3 ONE TWO2 NULL 
4 ONE TWO2 THREE1 
5 ONE TWO3 THREE1 
5 ONE TWO3 THREE2 

行3すなわち、それ自体がL1のために、それはこの場合、最初の行には、L1データを含む最新の行に移動する必要があり、L2の値を持っています。

私はanalyticsとconnect句を調べてみましたが、解決策の中で私の頭を得ることはできません。
アイデア

答えて

5

更新:私の最初の答えよりもはるかに簡単な解決策があります。それは私がそれゆえ(としてしばしばTom Kyteのおかげで)最初にここでそれを置く、より読みやすく、よりエレガントです:

SQL> SELECT seq, 
    2   last_value(CASE 
    3      WHEN lvl = 1 THEN 
    4      descr 
    5     END IGNORE NULLS) over(ORDER BY seq) L1, 
    6   last_value(CASE 
    7      WHEN lvl = 2 THEN 
    8      descr 
    9     END IGNORE NULLS) over(ORDER BY seq) L2, 
10   last_value(CASE 
11      WHEN lvl = 3 THEN 
12      descr 
13     END IGNORE NULLS) over(ORDER BY seq) L3 
14 FROM TEST; 

     SEQ L1   L2   L3 
---------- ---------- ---------- ---------- 
     1 ONE     
     2 ONE  TWO1  
     3 ONE  TWO2  
     4 ONE  TWO2  THREE1 
     5 ONE  TWO3  THREE1 
     6 ONE  TWO3  THREE2 

私の最初の溶液を以下に示します。

SQL> SELECT seq, 
    2   MAX(L1) over(PARTITION BY grp1) L1, 
    3   MAX(L2) over(PARTITION BY grp2) L2, 
    4   MAX(L3) over(PARTITION BY grp3) L3 
    5 FROM (SELECT seq, 
    6     L1, MAX(grp1) over(ORDER BY seq) grp1, 
    7     L2, MAX(grp2) over(ORDER BY seq) grp2, 
    8     L3, MAX(grp3) over(ORDER BY seq) grp3 
    9    FROM (SELECT seq, 
10       CASE WHEN lvl = 1 THEN descr END L1, 
11       CASE WHEN lvl = 1 AND descr IS NOT NULL THEN ROWNUM END grp1, 
12       CASE WHEN lvl = 2 THEN descr END L2, 
13       CASE WHEN lvl = 2 AND descr IS NOT NULL THEN ROWNUM END grp2, 
14       CASE WHEN lvl = 3 THEN descr END L3, 
15       CASE WHEN lvl = 3 AND descr IS NOT NULL THEN ROWNUM END grp3 
16      FROM test)) 
17 ORDER BY seq; 

     SEQ L1   L2   L3 
---------- ---------- ---------- ---------- 
     1 ONE     
     2 ONE  TWO1  
     3 ONE  TWO2  
     4 ONE  TWO2  THREE1 
     5 ONE  TWO3  THREE1 
     6 ONE  TWO3  THREE2 
+0

それは本当に甘い、まさに私が探していたもので、アナリティクスを介してやってもらえると思う。 RaxとCalmarにも感謝します。 – Patrick

+0

はい、はるかに良い、ありがとう。 はい、私はあなたも最初のレスポンスのスタイルからトム・キテのファンだと推測していました。 – Patrick

0

レベルは3つ(または固定数)ですか?

SELECT COUNTER.SEQ AS SEQ, A.DESCR AS L1, B.DESCR AS L2, C.DESCR AS L3 
FROM TABLE AS COUNTER, TABLE AS A, TABLE AS B, TABLE AS C 
WHERE 
A.SEQ = 
    (SELECT MAX(D.SEQ) FROM TABLE AS D 
    WHERE D.LVL = 1 AND D.SEQ <= COUNTER.SEQ) AND 
B.SEQ = 
    (SELECT MAX(D.SEQ) FROM TABLE AS D 
    WHERE D.LVL = 2 AND D.SEQ <= COUNTER.SEQ) AND 
C.SEQ = 
    (SELECT MAX(D.SEQ) FROM TABLE AS D 
    WHERE D.LVL = 3 AND D.SEQ <= COUNTER.SEQ) 

もしそうなら(それがわずかな変更を必要とするかもしれない「ブラインド」のコードですので、私はこのコンピュータから、それを実行することはできません)、あなたは非常に非効率的であるようなものを、使用することができますが、私は作品を信じます

+0

はい、レベルが固定されている - 実際タスクはレベル3から9を使用します。その考えに感謝し、私はそれを考慮しませんでした。それでも自己結合なしで処理するためのきれいな方法があることを望んでいます。 – Patrick

0

connect句を使用するには、実際にはいくつかのリンクが必要です。したがって、必要な値を持つ前の行へのリンクを持つ列があるはずです。これらのフィールドでは、他のレベルをチェックするために各行に対して2つの副選択を持つ必要があるため、選択するのは難しいです。

適切な場合は、pl/sqlプロシージャを使用します。

declare 
    cursor c_cur is 
    select * from test order by seq asc; 

lvl1 test.descr%type := null; 
lvl2 test.descr%type := null; 
lvl3 test.descr%type := null; 

begin 

for rec in c_cur loop 
    if rec.lvl = 1 then 
     lvl1 := rec.descr; 
    elsif rec.lvl = 2 then 
     lvl2 := rec.descr; 
    elsif rec.lvl = 3 then 
     lvl3 := rec.descr; 
    end if; 
    dbms_output.put_line(rec.seq||','||nvl(lvl1, 'null')||','||nvl(lvl2, 'null')||','||nvl(lvl3, 'null')); 
end loop; 

end; 
/
関連する問題