Вопрос

Я пытаюсь построить запрос таким образом, чтобы некоторый столбец был создан из предыдущей соответствующей строки.Например, со следующими данными:

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 он сам имеет значение для L2, для L1 он должен перейти к самой последней строке, которая содержит данные L1, в данном случае к первой строке.

Я пытался посмотреть на analytics и предложение connect, но не могу найти решение.
Есть какие-нибудь идеи?

Это было полезно?

Решение

Обновить:существует гораздо более простое решение, чем мой первый ответ.Это более читабельно И элегантно, поэтому я помещу его здесь первым (как часто, благодаря Том Кайт):

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, вам действительно понадобится какая-то ссылка между строками.Таким образом, должен быть какой-то столбец, который содержал бы ссылку на предыдущую строку, имеющую требуемое значение.С этими полями довольно сложно сделать один выбор, так как вам нужно иметь 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;
/
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top