选择有效的进入和退出记录

时间:2017-04-28 16:25:52

标签: sql oracle select union

以下是我所拥有的表格中的样本

F_ID     R_ID       DATE    Col_A   Col_B   Col_C  Day_Rec  Update_No
 12      158      20161008    01      99     99     1        -
 12      158      20161012    01      01     99     1        -
 12      158      20161019    01      02     10     1        -
 12      158      20161019    99      01     10     2        1
 12      158      20161019    99      02     10     2        2
 12      160      20161006    01      99     01     1        -
 12      160      20161006    01      99     02     2        1
 12      160      20161011    99      01     99     1        -
 17      167      20161013    99      01     01     1        - 
 17      167      20161016    99      02     99     1        -
 17      167      20161020    02      01     10     1        -
 17      174      20161010    99      01     01     1        -
 17      174      20161012    01      02     11     1        -
 17      174      20161017    99      02     10     1        -
 17      174      20161017    99      96     10     2        1
 17      174      20161017    99      07     10     2        2
 17      174      20161017    99      99     10     2        3

对于每个F_ID,R_ID:

When Col_A or Col_B = '01' and Col_C <>'10' - **It is an entry record**
When Col_C = '10' - **It is an exit record**

Day_Rec = 1 means it is the first entry on that date
Day_Rec = 2 means it is the modification on the same date

Update_No - Incremental modification tracker

Update_No is missing when Day_Rec = 1 because its not a modification 
Update_No = 1 or 2 or 3..... when Day_Rec = 2 modified multiple times on same date

同一日期可能有多项修改,但Day_Rec仍然只有2。 Update_No

跟踪多个更新

这里的逻辑是

1. Select the earliest valid entry record. 
   If there is a modification on that earliest date select the entry record with Day_Rec = 2 and highest Update_No 
   **and** 
2. Select the latest exit record.
   If there is a modification on that latest date select the exit record with Day_Rec = 2 and highest Update_No  for each F_ID, R_ID

我想选择这样,我为每个F_ID和R_ID获得一个有效的条目记录和一个有效的退出记录。仅当每个F_ID和R_ID都具有有效的进入和退出记录

F_ID   R_ID    DATE     Col_A   Col_B   Col_C  Day_Rec Update_No
12     158    20161008    01      99     99      1       -      ->  Entry record
12     158    20161019    99      02     10      2       2      ->  Exit Record
17     167    20161013    99      01     01      1       -      ->  Entry record
17     167    20161020    02      01     10      1       -      ->  Exit Record
17     174    20161010    99      01     01      1       -      ->  Entry record
17     174    20161017    99      99     10      2       3      ->  Exit Record

我有以下查询来按日期获取排序和退出记录

SELECT * FROM (
SELECT your_table.*, ROW_NUMBER() OVER(PARTITION BY F_ID, R_ID order by DATE) as rn, 'Entry record' as rec FROM your_table WHERE (Col_A = '01' or Col_B = '01') and Col_C <> '10'
    union all
SELECT your_table.*, ROW_NUMBER() OVER(PARTITION BY F_ID, R_ID order by DATE DESC) as rn, 'Exit record' as rec FROM your_table WHERE Col_C = '10'
) t3
where rn = 1
ORDER BY F_ID, R_ID, DATE

但是如何考虑'Day_Rec'或'Update_No'字段。它也不会让我“只有当每个F_ID和R_ID条件都存在入口和出口记录时”

更新

我在选择查询的开头尝试了'Case when'而没有运气。如果在进入和退出记录的where条件中Day_Rec = 2,我似乎无法选择如何选择max(Update_No)

1 个答案:

答案 0 :(得分:0)

  1. 选择每个f_idr_id的第一个条目。然后外部加入对f_idr_id和日期的最新修改。 (截至12c,您可以使用OUTER APPLY。)
  2. 为出口做同样的事。
  3. UNION ALL两个查询。
  4. 获取结果,只留在结果集中有两行的f_idr_id
  5. 查询:

    select f_id, r_id, dte, col_a, col_b, col_c, day_rec, update_no 
    from
    (
      select 
        both.*,
        count(*) over (partition by f_id, r_id) as cnt
      from
      (
        select 
          e.f_id, 
          e.r_id, 
          e.dte, 
          coalesce(m.col_a, e.col_a) as col_a,
          coalesce(m.col_a, e.col_a) as col_b,
          coalesce(m.col_a, e.col_a) as col_c,
          coalesce(m.day_rec, e.day_rec) as day_rec,
          m.update_no
        from
        (
          select
            your_table.*,
            row_number() over(partition by f_id, r_id order by dte) as rn
          from your_table 
          where (col_a = '01' or col_b = '01') and col_c <> '10' and day_rec = 1
        ) e
        left join
        (
          select
            your_table.*,
            row_number() over(partition by f_id, r_id, dte order by update_no desc) as rn
          from your_table 
          where (col_a = '01' or col_b = '01') and col_c <> '10' and day_rec > 1
        ) m on m.f_id = e.f_id and m.r_id = e.r_id and m.dte = e.dte and m.rn = 1
        where e.rn = 1
        union all
        select 
          e.f_id, 
          e.r_id, 
          e.dte, 
          coalesce(m.col_a, e.col_a) as col_a,
          coalesce(m.col_a, e.col_a) as col_b,
          coalesce(m.col_a, e.col_a) as col_c,
          coalesce(m.day_rec, e.day_rec) as day_rec,
          m.update_no
        from
        (
          select
            your_table.*,
            row_number() over(partition by f_id, r_id order by dte) as rn
          from your_table 
          where col_c = '10' and day_rec = 1
        ) e
        left join
        (
          select
            your_table.*,
            row_number() over(partition by f_id, r_id, dte order by update_no desc) as rn
          from your_table 
          where col_c = '10' and day_rec > 1
        ) m on m.f_id = e.f_id and m.r_id = e.r_id and m.dte = e.dte and m.rn = 1
        where e.rn = 1
      ) both
    )
    where cnt = 2;