You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Oracle SQL按人员和指标筛选至首个异常行的实现方案

Oracle SQL 数据筛选实现:保留至首个异常记录(含该行)

我们有存储人员车辆时序数据的表,指标上报频率分日/月/季度,已通过LAG()和CASE生成了Status字段(OK表示上报合规,not OK表示异常)。现在需要按**人员(Person)+指标(Indicator)**分组筛选数据:

  • 保留每组中从第一条到首个Status='not OK'的所有行(包含该行)
  • 若组内无异常,则保留全部行

原始数据

IndicatorDatePrev_DateFrequencyrow_numStatus
km2024/04/032024/04/02Daily1OK
km2024/04/022024/04/01Daily2OK
km2024/04/012024/01/31Daily3not OK
km2024/01/312024/01/30Daily4not OK
gas in l2024/04/012024/01/01Quarterly1OK
gas in l2024/01/012023/01/01Quarterly2not OK
gas in l2023/01/012022/10/01Quarterly3OK
km2024/04/032024/04/02Daily1OK
km2024/04/022024/04/01Daily2OK
km2024/04/012024/03/31Daily3OK
km2024/03/31NoneDaily4not OK
gas in l2024/04/012024/01/01Quarterly1OK
gas in l2024/01/012023/01/01Quarterly2not OK
gas in l2023/01/012022/10/01Quarterly3OK

期望输出

IndicatorDatePrev_DateFrequencyrow_numStatus
km2024/04/032024/04/02Daily1OK
km2024/04/022024/04/01Daily2OK
km2024/04/012024/01/31Daily3not OK
gas in l2024/04/012024/01/01Quarterly1OK
gas in l2024/01/012023/01/01Quarterly2not OK
km2024/04/032024/04/02Daily1OK
km2024/04/022024/04/01Daily2OK
km2024/04/012024/03/31Daily3OK
km2024/03/31NoneDaily4not OK
gas in l2024/04/012024/01/01Quarterly1OK
gas in l2024/01/012023/01/01Quarterly2not OK

解决方案SQL

方法1:定位首个异常行号筛选

通过窗口函数找到每个分组内首个异常记录的row_num,再筛选行号不超过该值的记录:

WITH ranked_data AS (
    SELECT 
        t.*,
        MIN(CASE WHEN Status = 'not OK' THEN row_num ELSE NULL END) 
            OVER (PARTITION BY Person, Indicator) AS first_error_row
    FROM your_table t
)
SELECT 
    Person, Indicator, Date, Prev_Date, Frequency, row_num, Status
FROM ranked_data
WHERE 
    row_num <= NVL(
        first_error_row, 
        (SELECT MAX(row_num) FROM ranked_data rd WHERE rd.Person = ranked_data.Person AND rd.Indicator = ranked_data.Indicator)
    )
ORDER BY Person, Indicator, row_num;

方法2:累计异常次数标记

通过累计异常次数,保留累计次数≤1的行(0表示未出现异常,1表示刚出现第一个异常):

WITH data_with_flag AS (
    SELECT 
        t.*,
        SUM(CASE WHEN Status = 'not OK' THEN 1 ELSE 0 END) 
            OVER (PARTITION BY Person, Indicator ORDER BY row_num ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS error_count
    FROM your_table t
)
SELECT 
    Person, Indicator, Date, Prev_Date, Frequency, row_num, Status
FROM data_with_flag
WHERE error_count <= 1
ORDER BY Person, Indicator, row_num;

说明

  • 方法1通过定位首个异常行号,直接筛选范围;NVL处理无异常场景,取分组最大行号保留全部数据。
  • 方法2通过累计计数标记,逻辑更直观,无需额外子查询处理无异常情况。

内容的提问来源于stack exchange,提问作者goldmariek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 10:02:39