سؤال

أحاول بناء استفسار بحيث يتم بناء بعض العمود من صف مطابق سابق. على سبيل المثال مع البيانات التالية:

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، يجب أن تذهب إلى أحدث صف يحتوي على بيانات L1، في هذه الحالة الصف الأول.

لقد حاولت النظر في Analytics وشرط الاتصال ولكن لا يمكنني الحصول على رأسي حول حل.
أيه أفكار؟

هل كانت مفيدة؟

المحلول

تحديث: هناك حل أبسط بكثير من إجابتي الأولى. إنه أكثر قابلية للقراءة وأكثر أناقة، لذلك سأضعه هنا أولا (كما في كثير من الأحيان، بفضل توم كيت):

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

نصائح أخرى

هل لديك 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)

لاستخدام جملة Connect، ستحتاج في الواقع إلى صفوف الرابط بين الصفوف. لذلك يجب أن يكون هناك بعض العمود الذي سيكون له ارتباط بالصف السابق الذي يحتوي على القيمة المطلوبة. مع هذه الحقول، من الصعب كيندا أن تجعل واحدة تحدد واحدة تحتاج إلى مجموعتي فرعية لكل صف للتحقق من المستويات الأخرى.

أود استخدام إجراء 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;
/
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top