选择同一表格中最长日期和最大日期之前的日期的记录

时间:2017-04-18 16:08:54

标签: sql oracle select join union

我有下表

R_ID    DATE    Col_A   Col_B   Col_C
158   20161008    01      01     99
158   20161012    01      01     99
158   20161019    01      02     10
158   20161022    99      01     10

我想选择这样我得到以下结果

R_ID    DATE    Col_A   Col_B   Col_C
158   20161008    01      01     99
158   20161022    99      01     10

这里的逻辑是

1. 'select max date' for record with Col_C = '10' for a particular R_ID and 
2. When Col_A or Col_B = '01' and Col_C <> '10' select the minimum Date which is < Max_date used in 1st condition

我使用下面的联合条件

Select * from tbl1 T
where 
T.Col_C = '10' and 
T.DATE = (select max(T2.DATE) from tbl1 T2
                                 where
                                 T2.Col_C = '10' and
                                 T3.R_ID = T.R_ID
          )

union

Select * from tbl1 K
where
(K.Col_A = '01' or K.Col_B = '01') and 
K.Col_C <> '10' and
K.DATE = (select min(K2.DATE) from tbl1 K2 where 
                      (K2.Col_A = '01' or K2.Col_B = '01') and 
                       K2.Col_C <> '10' and
                       K2.R_ID = K.R_ID   
          ) and 

--K.DATE < T.DATE-- How do I use this condition within union?

我希望能够在评论中使用条件,但无法找到正确的语法

我已更新条件

2 个答案:

答案 0 :(得分:0)

这是一种蛮力方法:

    WITH aset
     AS (SELECT 158 rid, DATE '2016-10-08' d, '01' col_a, '01' col_b, '99' col_c FROM DUAL
         UNION ALL
         SELECT 158, DATE '2016-10-12', '01', '01', '99' FROM DUAL
         UNION ALL
         SELECT 158, DATE '2016-10-19', '01', '02', '10' FROM DUAL
         UNION ALL
         SELECT 158, DATE '2016-10-22', '99', '01', '10' FROM DUAL)
   , bset
     AS (  SELECT rid, MAX (d) maxd_10
             FROM aset
            WHERE col_c = '10'
         GROUP BY rid)
   , cset
     AS (  SELECT aset.rid, MIN (d) mind
             FROM aset INNER JOIN bset ON aset.rid = bset.rid
            WHERE aset.col_c <> '10'
         GROUP BY aset.rid)
SELECT aset.*
  FROM aset
       INNER JOIN bset
           ON aset.rid = bset.rid
          AND aset.d = bset.maxd_10
          AND col_c = '10'
UNION ALL
SELECT aset.*
  FROM aset
       INNER JOIN cset
           ON aset.rid = cset.rid
          AND aset.d = cset.mind
          AND aset.col_c <> '10';

结果:

RID  D           COL_A COL_B COL_C 
158  10/22/2016  99    01    10    
158  10/08/2016  01    01    99    

答案 1 :(得分:0)

分析函数可能对此有所帮助。

with dataset as (select 158 r_id, date '2016-10-08' value_date, '01' col_a, '01' col_b, '99' col_c from dual
                 union all
                 select 158, date '2016-10-12', '01', '01', '99' from dual
                 union all
                 select 158, date '2016-10-19', '01', '02', '10' from dual
                 union all
                 select 158, date '2016-10-22', '99', '01', '10' from dual)

select d3.*
from   (select d2.*,
               min(case when d2.col_c <> '10' and
                             '01' in (d2.col_a, d2.col_b) and
                             d2.value_date < d2.ceiling_date then d2.value_date
                        else null
                   end) over (partition by d2.r_id
                              order by d2.value_date
                              rows between unbounded preceding and unbounded following) smallest_date
        from   (select d.*,
                       max(case when d.col_c = '10' then d.value_date else null end)
                       over (partition by d.r_id
                             order by d.value_date
                             rows between unbounded preceding and unbounded following) ceiling_date
                from   dataset d) d2) d3
where d3.ceiling_date is not null        -- ceiling_date contains null if we were unable to find row with '10' in COL_C for specified r_id - remove such rows from result set
  and (d3.value_date = d3.ceiling_date   -- here we presume that combination of r_id + value_date gives us unique row
    or d3.value_date = d3.smallest_date); -- otherwise we should add some column(s) that help us decide what rows do we need (row_number() with custom order by clause may be helpful)