试图查找Oracle SQL中状态字段已更改的最近日期

试图查找Oracle SQL中状态字段已更改的最近日期,sql,oracle,Sql,Oracle,我有一个表格,显示了位置ID的LOCN_ID的完整历史记录,其中包括一个ACTIVE_状态字段,显示a表示ACTIVE,或I表示inactive。每次位置的活动状态更改时,都会创建一条新记录,其中包含一个新的OP_日期。但是,每当表中的外部可见字段发生更改时,也会创建另一条具有新操作日期的记录 对于表中的每个LOCN_ID,我需要能够找到ACTIVE_STATUS字段更改为I或A的最新OP_日期。我不关心外部可视字段何时更改。对于示例中显示的LOCN_ID,结果应为: OP_DATE

我有一个表格,显示了位置ID的LOCN_ID的完整历史记录,其中包括一个ACTIVE_状态字段,显示a表示ACTIVE,或I表示inactive。每次位置的活动状态更改时,都会创建一条新记录,其中包含一个新的OP_日期。但是,每当表中的外部可见字段发生更改时,也会创建另一条具有新操作日期的记录

对于表中的每个LOCN_ID,我需要能够找到ACTIVE_STATUS字段更改为I或A的最新OP_日期。我不关心外部可视字段何时更改。对于示例中显示的LOCN_ID,结果应为:

    OP_DATE       LOCN_ID   ACTIVE_STATUS
  12/9/11 7:34     558732         I
在某些情况下,LOCN_ID的活动状态永远不会改变,在这种情况下,结果应该是该LOCN_ID最早的运行日期

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

您可以使用行号:

您可以使用行号:


我已使用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;

干杯

我使用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;

干杯

您必须处理这两种情况,即状态发生变化的行和状态不存在的行。滞后是很明显的,因为它是为了找到以前的值而设计的。可选的是较旧、较慢的自连接。我们还需要行号,因为您有复杂的条件排序。在第一部分的行_编号中,我们需要降序,然后在状态没有变化的情况下升序。可以这样做:

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

您必须处理两种情况,即状态发生变化的行和状态不存在的行。滞后是很明显的,因为它是为了找到以前的值而设计的。可选的是较旧、较慢的自连接。我们还需要行号,因为您有复杂的条件排序。在第一部分的行_编号中,我们需要降序,然后在状态没有变化的情况下升序。可以这样做:

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

这将返回2013年6月4日作为OP_日期,因为该日期的外部可视字段从N更改为Y,活动_状态保持为I。我需要结果显示11年9月12日,因为这是活动_状态从A更改为I的最近日期。@JNegoda。我懂了。我修正了处理这个问题的答案。这返回4/6/13作为操作日期,因为外部可见字段在该日期从N变为Y,活动状态保持为I。我需要结果显示11年9月12日,因为这是活动状态从A变为I的最近日期。@JNegoda。我懂了。我解决了这个问题。