2010-01-25 3 views
2

J'ai une table qui représente une décharge ligne par ligne des données lues à partir d'un format de fichier texte particulier. Chaque ligne peut représenter une ligne "maître" ou "détail", indiquée par le code rec_type. Je voudrais écrire une requête qui obtient les lignes «maître» à côté des lignes de détail associées. Je suis venu avec quelque chose qui fait le travail, mais il semble un peu hackish et suis intéressé par de meilleurs moyens le cas échéant.fenêtre de fonction analytique Oracle définie par des données

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'); 

résultat souhaité:

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 

Hypothèses:

  • enregistrements sont traités dans l'ordre du premier type de disque rec_seq
  • est un "100"
  • chaque "100" enregistrement a 1 ou plus "200 "enregistrements suivants

Remarque: ceci est pour Oracle 9i, mais nous devrions passer à 11g R1 cette année.

+0

+1 Bonnes données d'échantillon. –

Répondre

2

Voici ce que j'ai jusqu'à présent:

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; 

Comme vous pouvez le voir, je suis en utilisant la fonction d'analyse des rapports MAX avec une fenêtre en partant du haut de la déposer à la ligne actuelle, pour obtenir l'enregistrement «100» pertinent pour l'enregistrement «200» actuel; Puis, dans la requête externe, je rejette les enregistrements "100" inutiles.

Pour emp_name, j'ai dû ajouter le rec_seq avec les données pour que la fonction MAX prend toujours le record d'en-tête correct; puis dans la requête externe, je coupe le rec_seq.

J'ai joué avec d'autres fonctions analytiques et de la syntaxe, y compris FIRST_VALUE et la syntaxe KEEP, mais aucun de ceux-ci semblent rendre ce travail plus simple; la difficulté est que la fenêtre est définie par la valeur de rec_type au lieu d'être un décalage constant.

+1

@Jeffrey: vous faites un seul passage sur les données, vous ne serez pas en mesure d'interroger cela plus efficacement. Comme vous le savez sans doute le modèle est « hackish » (maître et détail dans la même table) et par conséquent toutes les requêtes sur un modèle air bizarre :) –

1

Dans un désir de simplicité, pensez-vous qu'il vaut la peine de charger chaque type d'enregistrement dans une table d'importation séparée avant le traitement?

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   

Cela pourrait se prêter à une solution plus maintenable et vous permettra de sortir et de valider analysez le champ EMP_DATA séparés comm-séparément.

Juste une pensée - désolé si vous êtes à la recherche que pour une solution d'analyse.

+0

qui est ok - probablement une bonne idée de souligner que le tableau n'a pas été conçu pour ce genre de requête; c'est juste un journal d'activité d'importation. –

Questions connexes