【问题标题】:Trying to find the most recent date where a status field has changed in Oracle SQL尝试查找 Oracle SQL 中状态字段更改的最近日期
【发布时间】:2019-08-08 21:48:32
【问题描述】:

我有一个表格,其中显示了位置 ID (LOCN_ID) 的完整历史记录,其中包括一个 ACTIVE_STATUS 字段,显示 A 表示活动,或 I 表示非活动。每次位置的活动状态发生变化时,都会创建一条带有新 OP_DATE 的新记录。但是,每当表中的 EXTERNALLY_VISIBLE 字段发生更改时,也会创建另一个具有新 OP_DATE 的记录。

Here is an example of this.

对于表中的每个 LOCN_ID,我需要能够找到 ACTIVE_STATUS 字段更改的最新 OP_DATE(更改为 I 或 A)。我不在乎 EXTERNALLY_VISIBLE 字段何时更改。对于示例中显示的 LOCN_ID,结果应为:

    OP_DATE       LOCN_ID   ACTIVE_STATUS
  12/9/11 7:34     558732         I

在某些情况下,LOCN_ID 的活动状态永远不会改变,在这种情况下,结果应该是该 LOCN_ID 最旧的 OP_DATE。

如何在 Oracle SQL 中编写查询以显示每个 LOCN_ID 的所需输出?

【问题讨论】:

    标签: sql oracle


    【解决方案1】:

    您必须同时处理这两种情况,即存在状态更改的行和不存在状态的行。 Lag() 很明显,因为它旨在查找以前的值。可选的是较旧、较慢的自联接。我们还需要row_number(),因为您有复杂的条件排序。在row_number 作为第一部分,我们需要降序,然后在没有状态变化的情况下升序。可以在这里完成:

    select op_date, locn_id, active_status
      from (
        select a.*, row_number() 
                    over (partition by locn_id 
                          order by case when active_status <> las then sysdate-op_date end, 
                                   op_date) as rn
          from (select t.*, lag(active_status) over (partition by locn_id order by op_date) las 
                  from t) a) 
      where rn = 1
    

    dbfiddle demo

    【讨论】:

      【解决方案2】:

      你可以使用row_number():

      select t.*
      from (select t.*,
                   row_number() over (partition by locn_id order by op_date desc) as seqnum
            from (select t.*,
                         lag(active_status) over (partition by locn_id order by op_date) as prev_active_status
                  from t
                 ) t
             where prev_active_status <> active_status
           ) t
      where seqnum = 1;
      

      【讨论】:

      • 这将返回 4/6/13 作为 OP_DATE,因为 EXTERNALLY_VISIBLE 字段在该日期从 N 更改为 Y,并且 ACTIVE_STATUS 仍然是 I。我需要结果显示 12/9/11,因为那是ACTIVE_STATUS 更改的最近日期(在本例中从 A 到 I)。
      • @JNegoda 。 . .我懂了。我修复了解决这个问题的答案。
      【解决方案3】:

      我使用 LEFT JOIN 为您创建了以下查询:

      -- SAMPLE DATA
      WITH DATAA (OP_DATE, LOCN_ID, ACTIVE_STATUS, EXTERNALLY_VISIBLE)
      AS
      (
      SELECT TO_DATE('04/06/2013 2:31','MM/DD/RRRR HH24:MI'), 558732, 'I', 'Y' FROM DUAL UNION ALL
      SELECT TO_DATE('12/09/2011 7:34','MM/DD/RRRR HH24:MI'), 558732, 'I', 'N' FROM DUAL UNION ALL
      SELECT TO_DATE('10/02/2011 3:05','MM/DD/RRRR HH24:MI'), 558732, 'A', 'N' FROM DUAL UNION ALL
      SELECT TO_DATE('10/02/2011 2:59','MM/DD/RRRR HH24:MI'), 558732, 'I', 'N' FROM DUAL UNION ALL
      SELECT TO_DATE('10/02/2011 3:00','MM/DD/RRRR HH24:MI'), 558732, 'I', 'Y' FROM DUAL UNION ALL
      SELECT TO_DATE('04/09/2011 2:18','MM/DD/RRRR HH24:MI'), 558732, 'A', 'Y' FROM DUAL
      ),
      -- ACTUAL QUERY STARTS FROM HERE
      CTE(OP_DATE, LOCN_ID, ACTIVE_STATUS, EXTERNALLY_VISIBLE, RN) AS (
          SELECT
              D.*,
              ROW_NUMBER() OVER(
                  PARTITION BY LOCN_ID
                  ORDER BY
                      OP_DATE
              ) AS RN
          FROM
              DATAA D
      )
      SELECT
          OP_DATE,
          LOCN_ID,
          ACTIVE_STATUS
      FROM
          (
              SELECT
                  A.OP_DATE,
                  A.LOCN_ID,
                  A.ACTIVE_STATUS,
                  ROW_NUMBER() OVER(
                      PARTITION BY A.LOCN_ID
                      ORDER BY
                          A.OP_DATE DESC
                  ) AS RN
              FROM
                  CTE A
                  LEFT JOIN CTE B ON ( A.RN = B.RN + 1 )
              WHERE
                  ( A.ACTIVE_STATUS <> B.ACTIVE_STATUS
                    OR B.ACTIVE_STATUS IS NULL )
          )
      WHERE
          RN = 1;
      

      -- 输出--

      OP_DATE                LOCN_ID A
      ------------------- ---------- -
      09-12-2011 07:34:00     558732 I
      

      Demo

      干杯!!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-09-07
        • 1970-01-01
        • 1970-01-01
        • 2012-12-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多