Окно аналитической функции Oracle, определяемое данными

StackOverflow https://stackoverflow.com/questions/2130923

Вопрос

У меня есть таблица, которая представляет собой построчный дамп данных, считанных из определенного формата текстового файла.Каждая строка может представлять собой "основную" или "детальную" строку, обозначенную через rec_type код.Я хотел бы написать запрос, который получает "основные" строки рядом с соответствующими подробными строками.Я придумал кое-что, что справляется с этой задачей, но это кажется немного халтурным, и я заинтересован в лучших способах, если таковые имеются.

CREATE TABLE mdtest
 (rec_seq  NUMBER        PRIMARY KEY
 ,rec_type VARCHAR2(3)   NOT NULL
 ,rec_data VARCHAR2(100) NOT NULL);

INSERT INTO mdtest VALUES (1, '100', 'Bill Jones');
INSERT INTO mdtest VALUES (2, '200', '20080115,100.25');
INSERT INTO mdtest VALUES (3, '100', 'John Smith');
INSERT INTO mdtest VALUES (4, '200', '20090701,80.95');
INSERT INTO mdtest VALUES (5, '200', '20091231,110.35');

Желаемый результат:

SEQ_EMP  EMP_NAME    SEQ_DATA  EMP_DATA
=======  ==========  ========  ===============
      1  Bill Jones         2  20080115,100.25
      3  John Smith         4  20090701,80.95
      3  John Smith         5  20091231,110.35

Предположения:

  • записи обрабатываются в последовательности rec_seq
  • первый тип записи - это "100"
  • каждый "100" запись содержит 1 или более записей "200" записи , следующие

Примечание:это для Oracle 9i, однако в этом году мы должны перейти на 11g R1.

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

Решение

Вот что у меня есть на данный момент:

SELECT seq_emp 
      ,SUBSTR(emp_seq_name,10) emp_name 
      ,seq_data 
      ,emp_data 
FROM  (SELECT MAX(CASE WHEN rec_type = '100' THEN rec_seq END) 
              OVER (ORDER BY rec_seq 
                    ROWS BETWEEN UNBOUNDED PRECEDING 
                             AND CURRENT ROW) seq_emp 
             ,MAX(CASE 
                  WHEN rec_type = '100' 
                  THEN TO_CHAR(rec_seq,'fm00000000') || '|' || rec_data 
                  END) 
              OVER (ORDER BY rec_seq 
                    ROWS BETWEEN UNBOUNDED PRECEDING 
                             AND CURRENT ROW) emp_seq_name 
             ,rec_seq seq_data 
             ,rec_type 
             ,rec_data emp_data 
       FROM   mdtest) 
WHERE  rec_type = '200' 
ORDER BY seq_data; 

Как вы можете видеть, я использую аналитическую функцию MAX reporting с окном, начинающимся с верхней части набора и заканчивающимся текущей строкой, чтобы получить соответствующую запись "100" для текущей записи "200";затем во внешнем запросе я отбрасываю ненужные записи "100".

Чтобы получить emp_name, мне пришлось добавить rec_seq к данным, чтобы функция MAX по-прежнему выбирала правильную запись заголовка;затем во внешнем запросе я отключаю rec_seq .

Я играл с другими аналитическими функциями и синтаксисом, включая FIRST_VALUE и синтаксис KEEP, но ни один из них, похоже, не упрощает эту работу;трудность заключается в том, что окно определяется значением rec_type вместо некоторого постоянного смещения.

Другие советы

Стремясь к простоте, считаете ли вы, что стоит загружать каждый тип записи в отдельную таблицу импорта перед обработкой?

create table mdtest100 as select * from mdtest where rec_type = 100;

create table mdtest200 as select * from mdtest where rec_type = 200;

with mdtest_detail as
    (
    select
        (select max(m.rec_seq) from mdtest100 m 
         where m.rec_seq < r200.rec_seq) master_rec_seq,
        r200.* 
    from 
        mdtest200 r200
    )
select
    m.rec_seq seq_emp,
    m.rec_data emp_name,
    d.rec_seq seq_data,
    d.rec_data emp_data
from
    mdtest_detail d
        inner join mdtest100 m on m.rec_seq = d.master_rec_seq
order by
    seq_emp,
    seq_data;


    SEQ_EMP  EMP_NAME    SEQ_DATA   EMP_DATA          
    1        Bill Jones  2          20080115,100.25          
    3        John Smith  4          20090701,80.95          
    3        John Smith  5          20091231,110.35          

Это может оказаться более удобным в обслуживании решением и позволит вам проанализировать и проверить разделенное запятыми поле EMP_DATA отдельно.

Просто мысль - извините, если вы ищете только аналитическое решение.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top