由数据定义的Oracle分析函数窗口

时间:2010-01-25 08:03:32

标签: sql oracle oracle9i analytic-functions

我有一个表,表示从特定文本文件格式读取的数据的逐行转储。每行代表“主”或“详细”行,通过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”记录在
  • 之后有一个或多个“200”记录

注意:这适用于Oracle 9i,但我们今年应该升级到11g R1。

2 个答案:

答案 0 :(得分:2)

这是我到目前为止所拥有的:

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报告分析功能,其窗口从设置的顶部开始到当前行,以获得当前“200”记录的相关“100”记录;然后在外部查询中我丢弃了不需要的“100”记录。

要获取emp_name,我必须在rec_seq中附加数据,以便MAX函数仍然选择正确的头记录;然后在外部查询中,我关闭了rec_seq。

我使用过其他分析函数和语法,包括FIRST_VALUE和KEEP语法,但这些似乎都不能使这项工作更简单;困难在于窗口是由rec_type的值定义的,而不是一些常量偏移。

答案 1 :(得分:1)

为了简化,您认为在处理之前将每种记录类型加载到单独的导入表中是否值得?

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字段。

只是想一想 - 如果您只是在寻找Google Analytics解决方案,请抱歉。