尝试查找 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?