【问题标题】:Rolling 90 day date window in SQL OracleSQL Oracle 中的滚动 90 天日期窗口
【发布时间】:2021-11-16 14:55:03
【问题描述】:
SELECT *
  FROM (SELECT date'2021-05-06' AS tran_dt FROM dual UNION
        SELECT date'2021-05-24' FROM dual UNION
        SELECT date'2021-06-25' FROM dual UNION
        SELECT date'2021-07-02' FROM dual UNION
        SELECT date'2021-07-27' FROM dual UNION
        SELECT date'2021-08-16' FROM dual UNION
        SELECT date'2021-08-23' FROM dual UNION
        SELECT date'2021-10-01' FROM dual UNION
        SELECT date'2021-12-31' FROM dual)

你好

我正在使用 SQL Oracle 中的日期字段。

我正在尝试创建滚动窗口,该窗口返回第一行并在自上次返回行以来的日期 >90 时返回另一行。

在下面的示例中,我想计算并返回警报字段 = 是的位置。

如果有人有任何想法,不胜感激。

谢谢

Shee7

TRAN_DT    Alert    Days Since Last Alert
06/05/2021  Yes     0
24/05/2021  No      18
25/06/2021  No      50
02/07/2021  No      57
27/07/2021  No      82
16/08/2021  Yes     102
23/08/2021  No      7
01/10/2021  No      46
31/12/2021  Yes     137

【问题讨论】:

    标签: sql oracle oracle11g


    【解决方案1】:

    你可以使用递归

    with firstr as (
      -- a row to start with
      select TRAN_DT
      from (
        select t.*
         , row_number() over(order by TRAN_DT) rn
        from trans t
      )
      where rn=1
    ),
    cte(TRAN_DT) as (
      select * 
      from firstr
      union all
      select t.*
      from cte c
      join trans t on t.TRAN_DT >= c.TRAN_DT + 90 and not exists (
                   select 1 
                   from trans t2 
                   where t2.TRAN_DT >= c.TRAN_DT + 90 and t2.TRAN_DT < t.TRAN_DT)
    )
    select * 
    from cte;
    

    【讨论】:

      【解决方案2】:

      也许会有第三个答案

      with tab1 as (
      SELECT TRAN_DT
        FROM (SELECT TO_DATE('20210506','YYYYMMDD') TRAN_DT FROM DUAL UNION
              SELECT TO_DATE('20210524','YYYYMMDD') TRAN_DT FROM DUAL UNION
              SELECT TO_DATE('20210625','YYYYMMDD') TRAN_DT FROM DUAL UNION
              SELECT TO_DATE('20210702','YYYYMMDD') TRAN_DT FROM DUAL UNION
              SELECT TO_DATE('20210727','YYYYMMDD') TRAN_DT FROM DUAL UNION
              SELECT TO_DATE('20210816','YYYYMMDD') TRAN_DT FROM DUAL UNION
              SELECT TO_DATE('20210823','YYYYMMDD') TRAN_DT FROM DUAL UNION
              SELECT TO_DATE('20211001','YYYYMMDD') TRAN_DT FROM DUAL UNION
              SELECT TO_DATE('20211231','YYYYMMDD') TRAN_DT FROM DUAL)
      )
      , tab2 as (
      select t1.tran_dt dt,
             row_number() over(order by t1.tran_dt) rn
        from tab1 t1
      )
      , t0(dt, rn, temp) as (
      select t1.dt, rn, t1.dt from tab2 t1 where t1.rn = 1
      union all
      select t2.dt, 
             t2.rn, 
             case when t2.dt - t0.temp > 90 then t2.dt else t0.temp end 
        from tab2 t2, t0 
       where t0.rn + 1 = t2.rn
      )
      select t1.dt, 
             case when t1.dt = t1.temp then 'yes' else 'no' end, 
             nvl(t1.dt - lag(t1.temp) over(order by t1.rn), 0)
        from t0 t1
      

      第三个答案,也许还有第四个

      with tab1 as (
      SELECT TRAN_DT
        FROM (SELECT TO_DATE('20210506','YYYYMMDD') TRAN_DT FROM DUAL UNION
              SELECT TO_DATE('20210524','YYYYMMDD') TRAN_DT FROM DUAL UNION
              SELECT TO_DATE('20210625','YYYYMMDD') TRAN_DT FROM DUAL UNION
              SELECT TO_DATE('20210702','YYYYMMDD') TRAN_DT FROM DUAL UNION
              SELECT TO_DATE('20210727','YYYYMMDD') TRAN_DT FROM DUAL UNION
              SELECT TO_DATE('20210816','YYYYMMDD') TRAN_DT FROM DUAL UNION
              SELECT TO_DATE('20210823','YYYYMMDD') TRAN_DT FROM DUAL UNION
              SELECT TO_DATE('20211001','YYYYMMDD') TRAN_DT FROM DUAL UNION
              SELECT TO_DATE('20211231','YYYYMMDD') TRAN_DT FROM DUAL)
      )
      , tab2 as (
      select t1.tran_dt dt
        from tab1 t1
       order by t1.tran_dt
       fetch next 1 row only
      )
      , t0(dt) as (
      select t1.dt from tab2 t1
      union all
      select (select min(v1.TRAN_DT) from tab1 v1 where t1.dt + 90 < v1.TRAN_DT)
        from t0 t1
       where t1.dt is not null
      )
      select t1.dt
        from t0 t1
       where t1.dt is not null
      

      【讨论】:

        【解决方案3】:

        从 Oracle 12 开始,这是 MATCH_RECOGNIZE 用于的查询类型:

        SELECT tran_dt,
               alert,
               tran_dt
                 - LAG(CASE alert WHEN 'Yes' THEN tran_dt END, 1, tran_dt)
                     IGNORE NULLS OVER (ORDER BY tran_dt)
                 AS days
        FROM   table_name
        MATCH_RECOGNIZE (
          ORDER BY tran_dt
          MEASURES
            CLASSIFIER() AS alert
          ALL ROWS PER MATCH
          PATTERN ( "Yes" "No"* )
          DEFINE
            "No" AS tran_dt <= "Yes".tran_dt + INTERVAL '90' DAY
        )
        

        在 Oracle 12 之前,您可以使用递归查询:

        WITH dates (tran_dt, rn) AS (
          SELECT tran_dt,
                 ROW_NUMBER() OVER (ORDER BY tran_dt) AS rn
          FROM   table_name
        ),
        rolling_dates (tran_dt, alert, rn, days, last_alert) AS (
          SELECT tran_dt, 'Yes', rn, 0, tran_dt
          FROM   dates
          WHERE  rn = 1
        UNION ALL
          SELECT d.tran_dt,
                 CASE
                 WHEN d.tran_dt <= r.last_alert + INTERVAL '90' DAY
                 THEN 'No'
                 ELSE 'Yes'
                 END,
                 d.rn,
                 d.tran_dt - r.last_alert,
                 CASE
                 WHEN d.tran_dt <= r.last_alert + INTERVAL '90' DAY
                 THEN r.last_alert
                 ELSE d.tran_dt
                 END
          FROM   rolling_dates r
                 INNER JOIN dates d
                 ON (r.rn + 1 = d.rn)
        )
        SELECT tran_dt,
               alert,
               days
        FROM   rolling_dates;
        

        这两个输出:

        TRAN_DT ALERT DAYS
        2021-05-06 00:00:00 Yes 0
        2021-05-24 00:00:00 No 18
        2021-06-25 00:00:00 No 50
        2021-07-02 00:00:00 No 57
        2021-07-27 00:00:00 No 82
        2021-08-16 00:00:00 Yes 102
        2021-08-23 00:00:00 No 7
        2021-10-01 00:00:00 No 46
        2021-12-31 00:00:00 Yes 137

        db小提琴here

        【讨论】:

          猜你喜欢
          • 2020-09-29
          • 2021-10-30
          • 2021-08-13
          • 2020-10-21
          • 2022-01-23
          • 2021-07-08
          • 2011-04-23
          • 2010-10-18
          • 2020-05-14
          相关资源
          最近更新 更多