Последнее изменение данных с T в качестве статуса в Oracle SQL - PullRequest
0 голосов
/ 04 сентября 2018

Мои данные приведены ниже

В приведенном ниже примере последняя запись имеет T, а последнее вхождение T было обновлено 3 апреля-17, поэтому необходимо отобразить строку

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 было обновлено 23 февраля-18, поэтому необходимо отобразить строку

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

Ответы [ 4 ]

0 голосов
/ 05 сентября 2018

Предполагая, что 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

РЕДАКТИРОВАТЬ: ну, если у вас есть другие статуи, давайте сделаем это более надежным. На самом деле, это почти то же самое, что предлагал Хуан-Карлос-Оропеза, но он пропустил часть «ДИАПАЗОН МЕЖДУ ТЕКУЩЕЙ СТРОКОЙ И НЕЗАКОННЫМ СЛЕДУЮЩИМ».

Упс, это то же самое решение: порядок, используемый Хуаном-Карлосом-Оропезой по DESC вместо неограниченного числа последователей.

    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
0 голосов
/ 05 сентября 2018
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 здесь: http://sqlfiddle.com/#!4/458733/18

0 голосов
/ 05 сентября 2018
alter session set nls_date_format = 'dd-Mon-rr';

Решение (включая смоделированные данные в предложении with):

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

Пояснение:

В подзапросе мы добавляем два столбца к входным данным. Столбец RN дает ранг в каждом разделе на EMPNO и STATUS, в порядке убывания на EFFDT. LAST_STATUS использовал аналитическую версию функции LAST(), чтобы присвоить либо T, либо A в качестве последнего состояния для каждого EMP (и он присоединяет это значение к КАЖДОЙ строке для EMP независимо от каждого собственный ряд STATUS).

Во внешнем запросе нас интересует только сохранение EMP, где последний статус был T. Для этих строк мы хотим сохранить только те строки, где фактический статус строки на самом деле равен T (мы знаем, что это всегда будет включать в себя последнюю строку для этого EMP, кстати, и будет иметь RN = 1). Более того, нас интересуют только те строки, в которых RN равен 1 или, возможно, 2 (если для этого EMP есть хотя бы две строки со статусом T). Из этих либо одной, либо двух строк со статусом T для данного EMP мы хотим получить самую раннюю дату. Это будет ЕДИНСТВЕННАЯ дата, если для этого раздела нет строки с RN = 2; в противном случае это будет дата из предыдущей строки с RN = 2.

Во внешнем SELECT мы выбираем EMP, самую раннюю дату и статус, который мы уже знаем, это T (поэтому нам не нужна никакая работа для этого - на самом деле не ясно, почему третий столбец даже необходим, поскольку заранее известно, что он будет T во всех строках).

0 голосов
/ 05 сентября 2018

Это проблема острова и пропасти.

В cte вы пытаетесь выяснить, на каком острове последнее обновление T (t = 0)

SQL DEMO

WITH cte as (
  SELECT "EMP", 
         "EFFDT", 
         SUM(CASE WHEN "STATUS" <> 'T' 
                  THEN 1 
                  ELSE 0 
             END) OVER (partition by "EMP" ORDER BY "EFFDT" DESC) as t
  FROM Table1
)  
SELECT "EMP", MIN("EFFDT") as "EFFDT", MAX('T') as "STATUS"
FROM cte 
WHERE t = 0
GROUP BY "EMP"

OUTPUT

|   EMP |                 EFFDT | STATUS |
|-------|-----------------------|--------|
| 11367 | 2017-04-03 00:00:00.0 |      T |
| 20612 | 2018-02-23 00:00:00.0 |      T |
| 20644 | 2016-10-06 00:00:00.0 |      T |

Для отладки вы можете попробовать

SELECT *
FROM cte 

чтобы увидеть, как создаются t значения

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...