在 Oracle SQL 中选择行,直到满足不同对象的条件

问题描述 投票:0回答:1

在 Oracle SQL 中,我有来自不同人的汽车的时间序列数据(例如行驶公里数或以升为单位使用的汽油)。一些指标按工作日报告,其他指标按月或季度报告。 对于后续计算,我想在 SQL 中选择每个人的所有后续指标行,直到出现第一个报告差距。如果没有报告差距,我想选择每个人每个指标的所有行。

Person   | Indicator|Date      |Prev_Date |Frequency| row_num | Status
-------  | -------- | -------- |----------|---------| --------| ------
A        | km       |2024/04/03|2024/04/02|Daily    | 1       |   OK
A        | km       |2024/04/02|2024/04/01|Daily    | 2       |   OK
A        | km       |2024/04/01|2024/01/31|Daily    | 3       |   not OK
A        | km       |2024/01/31|2024/01/30|Daily    | 4       |   not OK
A        | gas in l |2024/04/01|2024/01/01|Quarterly| 1       |   OK
A        | gas in l |2024/01/01|2023/01/01|Quarterly| 2       |   not OK
A        | gas in l |2023/01/01|2022/10/01|Quarterly| 3       |   OK
B        | km       |2024/04/03|2024/04/02|Daily    | 1       |   OK
B        | km       |2024/04/02|2024/04/01|Daily    | 2       |   OK
B        | km       |2024/04/01|2024/03/31|Daily    | 3       |   OK
B        | km       |2024/03/31|None      |Daily    | 4       |   not OK
B        | gas in l |2024/04/01|2024/01/01|Quarterly| 1       |   OK
B        | gas in l |2024/01/01|2023/01/01|Quarterly| 2       |   not OK
B        | gas in l |2023/01/01|2022/10/01|Quarterly| 3       |   OK

我在 SQL 中使用 LAG() 将先前观察的时间戳附加到每一行。在此基础上,我添加了一个案例结构,如果根据指标的报告频率,当前观察日期和前一个观察日期之间的时间滞后是可以的,则表示“正常”。

对于每个人和指标,我现在想要选择行,直到第一行的状态为“不正常”。应包括此内容,但不应报告为此人报告的该指标的后续行。

有什么线索可以帮助那些无知的人如何到达那里吗?

期望的输出是:

Person   | Indicator|Date      |Prev_Date |Frequency| row_num | Status
-------  | -------- | -------- |----------|---------| --------| ------
A        | km       |2024/04/03|2024/04/02|Daily    | 1       |   OK
A        | km       |2024/04/02|2024/04/01|Daily    | 2       |   OK
A        | km       |2024/04/01|2024/01/31|Daily    | 3       |   not OK
A        | gas in l |2024/04/01|2024/01/01|Quarterly| 1       |   OK
A        | gas in l |2024/01/01|2023/01/01|Quarterly| 2       |   not OK
B        | km       |2024/04/03|2024/04/02|Daily    | 1       |   OK
B        | km       |2024/04/02|2024/04/01|Daily    | 2       |   OK
B        | km       |2024/04/01|2024/03/31|Daily    | 3       |   OK
B        | km       |2024/03/31|None      |Daily    | 4       |   not OK
B        | gas in l |2024/04/01|2024/01/01|Quarterly| 1       |   OK
B        | gas in l |2024/01/01|2023/01/01|Quarterly| 2       |   not OK
sql oracle window-functions
1个回答
0
投票

从 Oracle 12 开始,您可以使用

MATCH_RECOGNIZE
进行逐行模式匹配:

SELECT person,
       indicator,
       dt,
       prev_dt,
       frequency,
       row_num,
       status
FROM   table_name
       MATCH_RECOGNIZE(
         PARTITION BY person, indicator
         ORDER BY dt DESC
         MEASURES
           NEXT(dt)     AS prev_dt,
           CLASSIFIER() AS status,
           COUNT(*)     AS row_num
         ALL ROWS PER MATCH
         PATTERN (^ "OK"* "not OK")
         DEFINE "OK" AS CASE 
                        WHEN Frequency = 'Daily'
                        THEN NEXT(dt) + INTERVAL '1' DAY
                        WHEN Frequency = 'Quarterly'
                        THEN ADD_MONTHS(NEXT(dt), 3)
                        END = dt
       )

对于样本数据:

CREATE TABLE table_name (Person, Indicator, DT, Frequency ) AS
SELECT 'A', 'km',       DATE '2024-04-03', 'Daily'     FROM DUAL UNION ALL
SELECT 'A', 'km',       DATE '2024-04-02', 'Daily'     FROM DUAL UNION ALL
SELECT 'A', 'km',       DATE '2024-04-01', 'Daily'     FROM DUAL UNION ALL
SELECT 'A', 'km',       DATE '2024-01-31', 'Daily'     FROM DUAL UNION ALL
SELECT 'A', 'gas in l', DATE '2024-04-01', 'Quarterly' FROM DUAL UNION ALL
SELECT 'A', 'gas in l', DATE '2024-01-01', 'Quarterly' FROM DUAL UNION ALL
SELECT 'A', 'gas in l', DATE '2023-01-01', 'Quarterly' FROM DUAL UNION ALL
SELECT 'B', 'km',       DATE '2024-04-03', 'Daily'     FROM DUAL UNION ALL
SELECT 'B', 'km',       DATE '2024-04-02', 'Daily'     FROM DUAL UNION ALL
SELECT 'B', 'km',       DATE '2024-04-01', 'Daily'     FROM DUAL UNION ALL
SELECT 'B', 'km',       DATE '2024-03-31', 'Daily'     FROM DUAL UNION ALL
SELECT 'B', 'gas in l', DATE '2024-04-01', 'Quarterly' FROM DUAL UNION ALL
SELECT 'B', 'gas in l', DATE '2024-01-01', 'Quarterly' FROM DUAL UNION ALL
SELECT 'B', 'gas in l', DATE '2023-01-01', 'Quarterly' FROM DUAL;

输出:

指标 DT PREV_DT 频率 ROW_NUM 状态
A l 中的气体 2024-04-01 00:00:00 2024-01-01 00:00:00 季刊 1 好的
A l 中的气体 2024-01-01 00:00:00 2023-01-01 00:00:00 季刊 2 不好
A 公里 2024-04-03 00:00:00 2024-04-02 00:00:00 每日 1 好的
A 公里 2024-04-02 00:00:00 2024-04-01 00:00:00 每日 2 好的
A 公里 2024-04-01 00:00:00 2024-01-31 00:00:00 每日 3 不好
B l 中的气体 2024-04-01 00:00:00 2024-01-01 00:00:00 季刊 1 好的
B l 中的气体 2024-01-01 00:00:00 2023-01-01 00:00:00 季刊 2 不好
B 公里 2024-04-03 00:00:00 2024-04-02 00:00:00 每日 1 好的
B 公里 2024-04-02 00:00:00 2024-04-01 00:00:00 每日 2 好的
B 公里 2024-04-01 00:00:00 2024-03-31 00:00:00 每日 3 好的
B 公里 2024-03-31 00:00:00 每日 4 不好

小提琴

© www.soinside.com 2019 - 2024. All rights reserved.