如何从同一个表

时间:2017-04-21 15:25:44

标签: sql oracle select join union

我有下表

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   
          )

但是像我在同一个表上使用自联接一样使用联合返回给我一个垃圾数据。

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

3 个答案:

答案 0 :(得分:1)

可能是一种更简单的方法......但我认为这可以通过一些易于遵循/维护的步骤使用CTE(常见的表格表达式)

这将生成每个R_ID的最小日期的数据集和每个R_ID的最大数据集,然后将这些集合连接到基集并将结果联合起来以获得所需的结果。由于我们使用了一个联合,我们需要将它全部包装在一个选择中以获得正确的顺序。

m v

我将&#34; date&#34;的名称更改为mdate,以避免因为它是关键字而无法转义列名。我也没有包括你所有的限制标准。

答案 1 :(得分: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&#39; d查询

答案 2 :(得分:0)

问题在于,您可以获得与日期过滤器匹配的多行,并匹配一些COL_A,B,C条件,但其中说K.COL_C&lt;&gt; 10和K2.COL_C&lt;&gt; 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,则它在结构上与您的union查询类似。它还添加了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
)