Oracle根据条件获取最新变更日期

时间:2018-11-01 14:40:49

标签: sql oracle oracle11g

我有下表tbl_subscriptions。

+-----------+--------+----------+--------+
| Sub.Date  |   ID   | POSITION | STATUS |
+-----------+--------+----------+--------+
| 8/22/2018 | 254515 | BROWN    | OPEN   |
| 8/21/2018 | 254515 | ORANGE   | CLOSE  |
| 8/20/2018 | 254515 | RED      | CLOSE  |
| 8/19/2018 | 254515 | ORANGE   | CLOSE  |
| 8/18/2018 | 254515 | BLUE     | CLOSE  |
| 8/17/2018 | 254515 | BLUE     | CLOSE  |
| 8/16/2018 | 254515 | BLUE     | CLOSE  |
| 8/15/2018 | 254515 | BLUE     | CLOSE  |
| 8/14/2018 | 254515 | ORANGE   | CLOSE  |
| 8/13/2018 | 254515 | BLUE     | CLOSE  |
+-----------+--------+----------+--------+

我真的很想了解以下内容。我有成千上万个带有各种ID的条目。 我需要获取所有“打开”条目以及最近从“蓝色”更改为“其他位置”的时间。参见下文,最近,头寸已于2018年8月19日从蓝色更改为橙​​色。所以,我想看这样的数据。

+-----------+--------+----------+--------+-----------------+
| Sub.Date  |   ID   | POSITION | STATUS | Pos. Changed on |
+-----------+--------+----------+--------+-----------------+
| 8/22/2018 | 254515 | BROWN    | OPEN   | 8/19/2018       |
+-----------+--------+----------+--------+-----------------+

我什至不知道如何实现这一目标。使用Oracle查询至少可以做到这一点。

3 个答案:

答案 0 :(得分:0)

您可以将lag Windows功能用作:

select ttt.*,
(
  select max(tt.sub_date)
    from
  (  
    select t.*,
           lag(POSITION) over (partition by ID order by Sub_Date ) lg       
      from tab t 
  ) tt
  where STATUS != 'OPEN'
    and tt.POSITION = 'ORANGE'
    and tt.lg = 'BLUE'
) as changed_on
  from tab ttt
 where STATUS = 'OPEN';

SQL Fiddle Demo

答案 1 :(得分:0)

这是一种方法:

WITH your_table AS (SELECT to_date('22/08/2018', 'dd/mm/yyyy') sub_date, 254515 ID, 'BROWN' position, 'OPEN' status FROM dual UNION ALL
                    SELECT to_date('21/08/2018', 'dd/mm/yyyy') sub_date, 254515 ID, 'ORANGE' position, 'CLOSED' status FROM dual UNION ALL
                    SELECT to_date('20/08/2018', 'dd/mm/yyyy') sub_date, 254515 ID, 'RED' position, 'CLOSED' status FROM dual UNION ALL
                    SELECT to_date('19/08/2018', 'dd/mm/yyyy') sub_date, 254515 ID, 'ORANGE' position, 'CLOSED' status FROM dual UNION ALL
                    SELECT to_date('18/08/2018', 'dd/mm/yyyy') sub_date, 254515 ID, 'BLUE' position, 'CLOSED' status FROM dual UNION ALL
                    SELECT to_date('17/08/2018', 'dd/mm/yyyy') sub_date, 254515 ID, 'BLUE' position, 'CLOSED' status FROM dual UNION ALL
                    SELECT to_date('16/08/2018', 'dd/mm/yyyy') sub_date, 254515 ID, 'BLUE' position, 'CLOSED' status FROM dual UNION ALL
                    SELECT to_date('15/08/2018', 'dd/mm/yyyy') sub_date, 254515 ID, 'BLUE' position, 'CLOSED' status FROM dual UNION ALL
                    SELECT to_date('14/08/2018', 'dd/mm/yyyy') sub_date, 254515 ID, 'ORANGE' position, 'CLOSED' status FROM dual UNION ALL
                    SELECT to_date('13/08/2018', 'dd/mm/yyyy') sub_date, 254515 ID, 'BLUE' position, 'CLOSED' status FROM dual UNION ALL
                    SELECT to_date('21/08/2018', 'dd/mm/yyyy') sub_date, 254516 ID, 'BROWN' position, 'OPEN' status FROM dual UNION ALL
                    SELECT to_date('20/08/2018', 'dd/mm/yyyy') sub_date, 254516 ID, 'ORANGE' position, 'CLOSED' status FROM dual UNION ALL
                    SELECT to_date('19/08/2018', 'dd/mm/yyyy') sub_date, 254516 ID, 'RED' position, 'CLOSED' status FROM dual UNION ALL
                    SELECT to_date('18/08/2018', 'dd/mm/yyyy') sub_date, 254516 ID, 'ORANGE' position, 'CLOSED' status FROM dual UNION ALL
                    SELECT to_date('17/08/2018', 'dd/mm/yyyy') sub_date, 254516 ID, 'BLUE' position, 'CLOSED' status FROM dual UNION ALL
                    SELECT to_date('16/08/2018', 'dd/mm/yyyy') sub_date, 254516 ID, 'BLUE' position, 'OPEN' status FROM dual UNION ALL
                    SELECT to_date('15/08/2018', 'dd/mm/yyyy') sub_date, 254516 ID, 'BLUE' position, 'CLOSED' status FROM dual UNION ALL
                    SELECT to_date('14/08/2018', 'dd/mm/yyyy') sub_date, 254516 ID, 'BLUE' position, 'CLOSED' status FROM dual UNION ALL
                    SELECT to_date('13/08/2018', 'dd/mm/yyyy') sub_date, 254516 ID, 'ORANGE' position, 'CLOSED' status FROM dual UNION ALL
                    SELECT to_date('12/08/2018', 'dd/mm/yyyy') sub_date, 254516 ID, 'BLUE' position, 'CLOSED' status FROM dual UNION ALL
                    SELECT to_date('29/08/2018', 'dd/mm/yyyy') sub_date, 1 ID, 'BLUE' position, 'OPEN' status FROM dual UNION ALL
                    SELECT to_date('28/08/2018', 'dd/mm/yyyy') sub_date, 1 ID, 'BLUE' position, 'CLOSED' status FROM dual UNION ALL
                    SELECT to_date('27/08/2018', 'dd/mm/yyyy') sub_date, 1 ID, 'BLUE' position, 'OPEN' status FROM dual UNION ALL
                    SELECT to_date('26/08/2018', 'dd/mm/yyyy') sub_date, 1 ID, 'YELLOW' position, 'CLOSED' status FROM dual),
        mid_res AS (SELECT sub_date,
                           ID,
                           position,
                           status,
                           CASE WHEN LAG(position) OVER (PARTITION BY ID ORDER BY sub_date) = 'BLUE' AND position != 'BLUE' THEN sub_date END blue_to_non_blue_dt
                    FROM   your_table),
            res AS (SELECT sub_date,
                           ID,
                           position,
                           status,
                           blue_to_non_blue_dt,
                           last_value(blue_to_non_blue_dt IGNORE NULLS) OVER (PARTITION BY ID ORDER BY sub_date) latest_blue_to_non_blue_dt
                    FROM   mid_res)
SELECT sub_date,
       ID,
       position,
       status,
       latest_blue_to_non_blue_dt
FROM   res
WHERE  status = 'OPEN'
ORDER BY ID, sub_date DESC;

SUB_DATE            ID POSITION STATUS LATEST_BLUE_TO_NON_BLUE_DT
----------- ---------- -------- ------ --------------------------
29/08/2018           1 BLUE     OPEN   
27/08/2018           1 BLUE     OPEN   
22/08/2018      254515 BROWN    OPEN   19/08/2018
21/08/2018      254516 BROWN    OPEN   18/08/2018
16/08/2018      254516 BLUE     OPEN   13/08/2018

这是通过首先查找上一行为BLUE而当前行不是BLUE的行来实现的。然后,它会在随后的行中填充该值,然后最终进行过滤以仅显示打开的行。

我假设您可以为一个id拥有多个OPEN行,并且您希望每个OPEN行的最新更改日期,因此我添加了额外的示例数据来演示其外观(id的1和254516)。

答案 2 :(得分:0)

您可以仅使用窗口功能来完成此操作:

select t.*
from (select t.*,
             max(case when position = 'ORANGE' and prev_position = 'BLUE' then sub_date end) over (partition by id) as change_date
      from (select t.*,
                   lag(position) over (partition by ID order by sub_date) as prev_position
            from t
           ) t
      ) t
where status = 'OPEN';