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

Posted

技术标签:

【中文标题】尝试查找 Oracle SQL 中状态字段更改的最近日期【英文标题】:Trying to find the most recent date where a status field has changed in 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 的所需输出?

【问题讨论】:

【参考方案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

干杯!!

【讨论】:

以上是关于尝试查找 Oracle SQL 中状态字段更改的最近日期的主要内容,如果未能解决你的问题,请参考以下文章

在 Oracle SQL 中使用正则表达式在字符串字段中查找 Unicode 字符

oracle 查找某字段中含有回车换行的记录,请问怎么写SQL?

oracle 查找某字段中含有回车换行的记录,请问怎么写SQL?

用SQL语句查询出数据表中的字段名以及注释(Oracle)

oracle 如何查找特定字母开头的某个字段?

在另一个字段Oracle SQL中包含的一个字段中查找文本