Oracle sql中状态为T的上次更改数据

Oracle sql中状态为T的上次更改数据,sql,oracle,Sql,Oracle,我的数据如下 在下面的示例中,最新记录为T,T的最后一次出现时间为2017年4月3日,因此需要显示行 EMP EFFDT STATUS 11367 15-Apr-15 A 11367 14-Jun-15 A 11367 10-Aug-15 T 11367 2-Apr-17 A 11367 3-Apr-17 T * 11367 10-Apr-17 T 在以下示例中,最新记录为T,T的最后一次出现时间为2018年2月23日,因此需

我的数据如下

在下面的示例中,最新记录为T,T的最后一次出现时间为2017年4月3日,因此需要显示行

EMP     EFFDT     STATUS
11367   15-Apr-15   A
11367   14-Jun-15   A
11367   10-Aug-15   T
11367   2-Apr-17    A
11367   3-Apr-17    T *
11367   10-Apr-17   T
在以下示例中,最新记录为T,T的最后一次出现时间为2018年2月23日,因此需要显示行

EMP     EFFDT     STATUS
20612   4-Sep-16    A
20612   23-Feb-18   T *
20612   20-Jul-18   T
在下面的示例中,最新记录有T,这是唯一出现的记录,因此请显示它

EMP    EFFDT      STATUS
20644   12-Jul-15   A
20644   8-Aug-16    A
20644   6-Oct-16    T*
在下面的示例中,最新记录没有T,因此不需要显示

EMP    EFFDT      STATUS
21155   18-May-17   T
21155   21-Jun-17   A
21155   13-Mar-18   T
21155   15-Aug-18   A
我想要的输出应该是*标记的记录

EMP    EFFDT      STATUS
11367   3-Apr-17    T
20612   23-Feb-18   T
20644   6-Oct-16    T

这是一个孤岛和缺口问题

在cte中,您试图找出上次更新T=0时,哪个岛有T

对于调试,您可以尝试

SELECT *
FROM cte 
查看t值是如何创建的

WITH cte1
AS (
    SELECT A.*
        ,lag(STATUS, 1, 0) OVER (
            PARTITION BY EMP ORDER BY EFFDT
            ) AS PRIOR_STATUS
    FROM Table1 A
    )
SELECT EMP
    ,STATUS
    ,MAX(EFFDT) AS EFFDT
FROM cte1 A
WHERE A.STATUS = 'T'
    AND A.PRIOR_STATUS <> 'T'
GROUP BY EMP
    ,STATUS
SQL Fiddle在此:

解决方案包括with条款中的模拟数据:

说明:

在子查询中,我们向输入数据添加了两列。列RN按EMPNO和STATUS给出每个分区内的排名,按EFFDT降序排列。LAST_STATUS使用LAST函数的分析版本将T或A指定为每个EMP的最后状态,并将此值附加到EMP的每一行,而不管每一行的自身状态如何

在外部查询中,我们只想保留最后状态为T的EMP。对于这些行,我们只想保留实际状态为T的行。顺便说一下,这将始终包括该EMP的最后一行,并且它的RN=1。此外,我们只对RN为1或可能为2的行感兴趣,如果该EMP至少有两行状态为T。对于给定的EMP,在状态为T的一行或两行中,我们希望得到最早的日期。如果该分区没有RN=2的行,则这将是唯一的日期;否则,它将是前一行的日期,RN=2


在外部选择中,我们选择EMP、最早日期和我们已经知道的状态,它是T,因此我们不需要为此做任何工作-实际上,不清楚为什么需要第三列,因为事先知道所有行中都是T。

假设A和T是唯一的状态,这应该可以工作

WITH cte1
        AS (
            SELECT A.EMP, A.EFFDT, A.STATUS
                ,min(STATUS) OVER (
                    PARTITION BY EMP ORDER BY EFFDT RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING 
                    ) AS MIN_STATUS
            FROM Table1 A
            )
    SELECT
       cte1.EMP
      ,MIN(cte1.EFFDT) AS EFFDT
      ,MIN(cte1.STATUS) as STATUS
    FROM cte1
    WHERE cte1.MIN_STATUS = 'T'
    GROUP BY EMP
编辑:好吧,如果你有另一个雕像,让我们让它更坚固。事实上,这和胡安·卡洛斯·奥罗佩扎提议的差不多,但他错过了当前一排和无限下一部分之间的距离

哦,这是相同的解决方案:胡安·卡洛斯·奥罗佩扎(juan carlos oropeza)使用了描述无界跟随的顺序

    with emp_status_log (EMP, EFFDT, STATUS) as
(
    select 11367, to_date('15-Apr-15', 'dd-Mon-yy'), 'A' from dual union all
    select 11367, to_date('14-Jun-15', 'dd-Mon-yy'), 'A' from dual union all
    select 11367, to_date('10-Aug-15', 'dd-Mon-yy'), 'T' from dual union all
    select 11367, to_date( '2-Apr-17', 'dd-Mon-yy'), 'A' from dual union all
    select 11367, to_date( '3-Apr-17', 'dd-Mon-yy'), 'T' from dual union all
    select 11367, to_date('10-Apr-17', 'dd-Mon-yy'), 'T' from dual union all

    select 20612, to_date( '4-Sep-16', 'dd-Mon-yy'), 'A' from dual union all
    select 20612, to_date('23-Feb-18', 'dd-Mon-yy'), 'T' from dual union all
    select 20612, to_date('20-Jul-18', 'dd-Mon-yy'), 'T' from dual union all

    select 20644, to_date('12-Jul-15', 'dd-Mon-yy'), 'A' from dual union all
    select 20644, to_date( '8-Aug-16', 'dd-Mon-yy'), 'A' from dual union all
    select 20644, to_date( '6-Oct-16', 'dd-Mon-yy'), 'T' from dual union all

    select 21155, to_date('18-May-17', 'dd-Mon-yy'), 'T' from dual union all
    select 21155, to_date('21-Jun-17', 'dd-Mon-yy'), 'A' from dual union all
    select 21155, to_date('13-Mar-18', 'dd-Mon-yy'), 'T' from dual union all
    select 21155, to_date('15-Aug-18', 'dd-Mon-yy'), 'A' from dual
  )
,
-- End of simulated data (for testing only).
/* SQL query (solution) begins BELOW THIS LINE.
with--*/
cte1 as
( 
   select sl.*
     ,sum(decode(sl.STATUS, 'T', 0, 1)) OVER (
                       PARTITION BY sl.EMP ORDER BY sl.EFFDT RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING 
                       ) AS non_t_count
   from emp_status_log sl
)
select
   cte1.emp
 , min(cte1.effdt) as effdt
 , min(cte1.status) as status
from cte1
where cte1.non_t_count = 0
group by cte1.emp

那么您希望前一行在最后一个T之前,或者如果只有一个,则最后一个T?如果EMP没有T怎么办?对于EMP,如果最新的EFFDT记录有“T”,则必须考虑它。如果最新的EFFDT不是T,则不需要。如果您看到第一个样本的最新EFFDT记录是T,但它实际上在2017年4月3日更新,第二个样本的最新记录是T,但它实际上在2018年2月23日更新,第三个样本的最新记录是T,这是英语的唯一更新,不是我的第一个冷瓜杰,可以吗将该案例包括在示例数据中。还包括欲望输出。实际上是在2017年4月3日更新的。你的意思是什么?我看到在2017年4月10日也有更新。我想你需要澄清更新是什么意思。你能按我的问题中所示显示输出吗?编辑解释了场景。这就是为什么我要求你包含欲望输出。作为你问题的一部分:@sryi刚刚添加了它,因为我对stackoverflow不熟悉,所以它对我来说花了很少的时间。请您将您的答案与所需的输出一起发布,请…完成,但如果您不能为自己这样做,则不确定您是否能够理解代码的其余部分。我不认为这是一个空白和孤岛问题;我认为OP的例子有误导性。在状态a,a,T,a,a,T中从最早到最新的顺序中,OP希望第三行的日期是T的第一次出现,然后紧接着是两个a,最后一个状态是T。他用文字解释的是,如果最后一个状态是T,如果有任何其他状态没有提到连续,他想要T的第二个最新状态。没有差距和岛屿,那么。我们还有其他状态,比如研发
alter session set nls_date_format = 'dd-Mon-rr';
with
  simulated_data (EMP, EFFDT, STATUS) as (
    select 11367, to_date('15-Apr-15'), 'A' from dual union all
    select 11367, to_date('14-Jun-15'), 'A' from dual union all
    select 11367, to_date('10-Aug-15'), 'T' from dual union all
    select 11367, to_date( '2-Apr-17'), 'A' from dual union all
    select 11367, to_date( '3-Apr-17'), 'T' from dual union all
    select 11367, to_date('10-Apr-17'), 'T' from dual union all
    select 20612, to_date( '4-Sep-16'), 'A' from dual union all
    select 20612, to_date('23-Feb-18'), 'T' from dual union all
    select 20612, to_date('20-Jul-18'), 'T' from dual union all
    select 20644, to_date('12-Jul-15'), 'A' from dual union all
    select 20644, to_date( '8-Aug-16'), 'A' from dual union all
    select 20644, to_date( '6-Oct-16'), 'T' from dual union all
    select 21155, to_date('18-May-17'), 'T' from dual union all
    select 21155, to_date('21-Jun-17'), 'A' from dual union all
    select 21155, to_date('13-Mar-18'), 'T' from dual union all
    select 21155, to_date('15-Aug-18'), 'A' from dual
  )
-- End of simulated data (for testing only).
-- SQL query (solution) begins BELOW THIS LINE.
select emp, min(effdt) as eff_dt, 'T' as status
from   (
         select emp, effdt, status,
                row_number() over (partition by emp, status 
                                   order by effdt desc)           as rn,
                min(status) keep (dense_rank last order by effdt)
                             over (partition by emp)              as last_status
         from   simulated_data
       )
where  last_status = 'T' and status = 'T' and rn <= 2
group by emp
;
       EMP EFF_DT    STATUS
---------- --------- ------
     11367 03-Apr-17 T
     20612 23-Feb-18 T
     20644 06-Oct-16 T
WITH cte1
        AS (
            SELECT A.EMP, A.EFFDT, A.STATUS
                ,min(STATUS) OVER (
                    PARTITION BY EMP ORDER BY EFFDT RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING 
                    ) AS MIN_STATUS
            FROM Table1 A
            )
    SELECT
       cte1.EMP
      ,MIN(cte1.EFFDT) AS EFFDT
      ,MIN(cte1.STATUS) as STATUS
    FROM cte1
    WHERE cte1.MIN_STATUS = 'T'
    GROUP BY EMP
    with emp_status_log (EMP, EFFDT, STATUS) as
(
    select 11367, to_date('15-Apr-15', 'dd-Mon-yy'), 'A' from dual union all
    select 11367, to_date('14-Jun-15', 'dd-Mon-yy'), 'A' from dual union all
    select 11367, to_date('10-Aug-15', 'dd-Mon-yy'), 'T' from dual union all
    select 11367, to_date( '2-Apr-17', 'dd-Mon-yy'), 'A' from dual union all
    select 11367, to_date( '3-Apr-17', 'dd-Mon-yy'), 'T' from dual union all
    select 11367, to_date('10-Apr-17', 'dd-Mon-yy'), 'T' from dual union all

    select 20612, to_date( '4-Sep-16', 'dd-Mon-yy'), 'A' from dual union all
    select 20612, to_date('23-Feb-18', 'dd-Mon-yy'), 'T' from dual union all
    select 20612, to_date('20-Jul-18', 'dd-Mon-yy'), 'T' from dual union all

    select 20644, to_date('12-Jul-15', 'dd-Mon-yy'), 'A' from dual union all
    select 20644, to_date( '8-Aug-16', 'dd-Mon-yy'), 'A' from dual union all
    select 20644, to_date( '6-Oct-16', 'dd-Mon-yy'), 'T' from dual union all

    select 21155, to_date('18-May-17', 'dd-Mon-yy'), 'T' from dual union all
    select 21155, to_date('21-Jun-17', 'dd-Mon-yy'), 'A' from dual union all
    select 21155, to_date('13-Mar-18', 'dd-Mon-yy'), 'T' from dual union all
    select 21155, to_date('15-Aug-18', 'dd-Mon-yy'), 'A' from dual
  )
,
-- End of simulated data (for testing only).
/* SQL query (solution) begins BELOW THIS LINE.
with--*/
cte1 as
( 
   select sl.*
     ,sum(decode(sl.STATUS, 'T', 0, 1)) OVER (
                       PARTITION BY sl.EMP ORDER BY sl.EFFDT RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING 
                       ) AS non_t_count
   from emp_status_log sl
)
select
   cte1.emp
 , min(cte1.effdt) as effdt
 , min(cte1.status) as status
from cte1
where cte1.non_t_count = 0
group by cte1.emp