2017-04-21 78 views
1

每个用户的出入境记录我有以下表如何选择从同一个表

R_ID DATE Col_A Col_B Col_C 
158 20161008 01  99  99 
158 20161012 01  01  99 
158 20161019 01  02  10 
158 20161022 99  01  10 
160 20161006 01  99  01 
160 20161011 99  01  99 
160 20161017 99  01  10 
167 20161013 99  01  01 
167 20161016 99  02  99 
167 20161020 02  01  10 

我想在这里是选择这样的,我得到以下结果

R_ID DATE Col_A Col_B Col_C 
158 20161008 01  01  99  - Entry record 
158 20161022 99  01  10  - Exit Record 
160 20161006 01  99  01  - Entry record 
160 20161017 99  01  10  - Exit Record 
167 20161013 99  01  01  - Entry record 
167 20161020 02  01  10  - Exit Record 

For each 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** 

逻辑

1. Select the earliest entry record 
    **and** 
2. Select the latest exit record for each R_ID 

我想利用工会类似下面的...

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 
     ) 

但是像我这样在同一张桌子上用自联接做的联合正在给我返回一个垃圾数据。

这可以通过连接来实现吗?

回答

1

可能是一个更简单的方法...但我认为这确实是在几个容易遵循/保持使用的CTE(公共表表达式)

这产生于数据集一个与最小日期步骤对于每个R_ID和每个R_ID具有最大值的一个,然后将这些集合加入到基本集合中并结合结果以获得期望的结果。由于我们使用了一个联合,我们需要将它全部包装在一个选择中以获得正确的顺序。

With Data(R_ID, mDate, Col_A, Col_B, Col_C) as (
    SELECT 158, 20161008, 01,  99,  99 FROM DUAL UNION ALL 
    SELECT 158, 20161012, 01,  01,  99 FROM DUAL UNION ALL 
    SELECT 158, 20161019, 01,  02,  10 FROM DUAL UNION ALL 
    SELECT 158, 20161022, 99,  01,  10 FROM DUAL UNION ALL 
    SELECT 160, 20161006, 01,  99,  01 FROM DUAL UNION ALL 
    SELECT 160, 20161011, 99,  01,  99 FROM DUAL UNION ALL 
    SELECT 160, 20161017, 99,  01,  10 FROM DUAL UNION ALL 
    SELECT 167, 20161013, 99,  01,  01 FROM DUAL UNION ALL 
    SELECT 167, 20161016, 99,  02,  99 FROM DUAL UNION ALL 
    SELECT 167, 20161020, 02,  01,  10 FROM DUAL), 

MinRID as (SELECT R_ID, Min(mDate) MinDate from Data GROUP BY R_ID), 
MaxRID as (SELECT R_ID, Max(mdate) MaxDate from Data GROUP BY R_ID), 
Result as (SELECT A.R_ID, A.mDate, A.COL_A, A.COL_B, A.Col_C, 'Entry Record' as RecType 
       FROM Data A 
       INNER JOIN MinRID B 
        on B.R_ID = A.R_ID 
       and B.MinDate = A.mDate 

       UNION ALL 

       SELECT A.R_ID, A.mDate, A.COL_A, A.COL_B, A.Col_C, 'Exit Record' as RecType 
       FROM Data A 
       INNER JOIN maxRID C 
        on C.R_ID = A.R_ID 
       and C.MaxDate = A.mDate) 
SELECT * FROM Result ORDER BY R_ID, MDATE 

我将“date”的名称更改为mdate以避免必须转义列名,因为它是关键字。我也没有包括你所有的限制标准。

1

此解决方案有一个子查询,以便在两个方向上对所有DATE值进行排名。子查询用于UNION ALL以获得所需的输出。

with cte as (
    select R_ID 
     , DATE 
     , COL_A 
     , COL_B 
     , COL_C 
     , rank() over (partition by R_ID order by DATE asc, COL_A asc) as entry_rnk 
     , rank() over (partition by R_ID order by DATE desc, COL_A asc) as exit_rnk 
    from TBL1 
) 
select R_ID 
     , DATE 
     , COL_A 
     , COL_B 
     , COL_C 
     , 'Entry record' 
from cte 
where entry_rnk = 1 
union all 
select R_ID 
     , DATE 
     , COL_A 
     , COL_B 
     , COL_C 
     , 'Exit record' 
from cte 
where exit_rnk = 1 
order by 1, 5 
/

我会老实说:我忽略了发布的WHERE子句中的附加过滤器,因为没有解释它们应用了什么规则。也许你需要将它们包含在WITH子句和/或UNION的查询中

0

问题是你可以得到多个匹配日期过滤器的行,并匹配一些COL_A,B,C条件,但是在哪里说K.COL_C <> 10且K2.COL_C <> 10,但K.COL_C可能与K2.COL_C 或T.COL_C = 10和T2.COL_C = 10匹配或可能不匹配,但是T.COL_A和T.COL_B可能不匹配匹配T2.COL_A或T2.COL_B。

这是一个不使用联合的查询。如果您考虑将您的2 where子句更改为两者的OR,它在结构上与您的联合查询类似。它还添加了COL_A,COL_B和COL_C匹配。

Select 
BASE_TABLE.* 

from 
    tbl1 as BASE_TABLE, 

(select K2.R_ID, min(K2.DATE) as MINDATE, 
     K2.COL_A, K2.COL_B, K2.COL_C  
from tbl1 K2 
    where 
    (K2.Col_A = '01' or K2.Col_B = '01') and 
    K2.Col_C <> '10' 
    group by K2.R_ID, K2.COL_A, K2.COL_B, K2.COL_C) 
    AS ENTRY_FILTER , 

(select T2.R_ID, max(T2.DATE) as MAXDATE, 
     T2.COL_A,T2.COL_B, T2.COL_C  
from tbl1 T2 
          where 
          T2.Col_C = '10' 
    group by T2.R_ID, T2.COL_A,T2.COL_B, T2.COL_C 
) 
    AS EXIT_FILTER 

where 
(ENTRY_FILTER.R_ID = BASE_TABLE.R_ID 
AND BASE_TABLE.DATE = ENTRY_FILTER.MINDATE 
and BASE_TABLE.COL_A = ENTRY_FILTER.COL_A 
and BASE_TABLE.COL_B = ENTRY_FILTER.COL_B 
and BASE_TABLE.COL_C = ENTRY_FILTER.COL_C 
) 
or 
(
EXIT_FILTER.R_ID = BASE_TABLE.R_ID; 
AND BASE_TABLE.DATE = EXIT_FILTER.MAXDATE 
AND BASE_TABLE.COL_A = EXIT_FILTER.COL_A 
AND BASE_TABLE.COL_B = EXIT_FILTER.COL_B 
AND BASE_TABLE.COL_C = EXIT_FILTER.COL_C 
) 
相关问题