如何使用层次坐标计算差值,如下图

如何使用层次坐标计算差值,D列的差值规则是 ,C列的相邻异常数据的和加起来  , 除以异常个数,C列的异常数指的是不在100-200之间的数

image.png

FineReport 张宇 发布于 2025-10-23 11:17 (编辑于 2025-10-23 11:24)
1min目标场景问卷 立即参与
回答问题
悬赏:3 F币 + 添加悬赏
提示:增加悬赏、完善问题、追问等操作,可使您的问题被置顶,并向所有关注者发送通知
共2回答
最佳回答
0
CD20160914Lv8专家互助
发布于2025-10-23 11:19(编辑于 2025-10-23 14:11)

用数据库的功能,你这个要判断太多连续的数据了。层次坐标也不好弄。

上面要用下面的数据,下面又要用上面的数据,不好弄

WITH your_data AS (

    SELECT 'A' AS 类别, TO_TIMESTAMP('2025-10-19 00:00:00', 'YYYY-MM-DD HH24:MI:SS') AS 时间, 100.00 AS 数值 FROM DUAL UNION ALL

    SELECT 'A', TO_TIMESTAMP('2025-10-19 01:00:00', 'YYYY-MM-DD HH24:MI:SS'), 150.00 FROM DUAL UNION ALL

    SELECT 'A', TO_TIMESTAMP('2025-10-19 02:00:00', 'YYYY-MM-DD HH24:MI:SS'), 20.00 FROM DUAL UNION ALL

    SELECT 'A', TO_TIMESTAMP('2025-10-19 03:00:00', 'YYYY-MM-DD HH24:MI:SS'), 220.00 FROM DUAL UNION ALL

    SELECT 'A', TO_TIMESTAMP('2025-10-19 04:00:00', 'YYYY-MM-DD HH24:MI:SS'), 100.00 FROM DUAL UNION ALL

    SELECT 'A', TO_TIMESTAMP('2025-10-19 05:00:00', 'YYYY-MM-DD HH24:MI:SS'), 140.00 FROM DUAL UNION ALL

    SELECT 'A', TO_TIMESTAMP('2025-10-19 06:00:00', 'YYYY-MM-DD HH24:MI:SS'), 10.00 FROM DUAL UNION ALL

    SELECT 'A', TO_TIMESTAMP('2025-10-19 07:00:00', 'YYYY-MM-DD HH24:MI:SS'), 210.00 FROM DUAL UNION ALL

    SELECT 'A', TO_TIMESTAMP('2025-10-19 08:00:00', 'YYYY-MM-DD HH24:MI:SS'), 20.00 FROM DUAL UNION ALL

    SELECT 'A', TO_TIMESTAMP('2025-10-19 09:00:00', 'YYYY-MM-DD HH24:MI:SS'), 240.00 FROM DUAL UNION ALL

    SELECT 'A', TO_TIMESTAMP('2025-10-19 10:00:00', 'YYYY-MM-DD HH24:MI:SS'), 100.00 FROM DUAL UNION ALL

    SELECT 'A', TO_TIMESTAMP('2025-10-19 11:00:00', 'YYYY-MM-DD HH24:MI:SS'), 120.00 FROM DUAL UNION ALL

    SELECT 'A', TO_TIMESTAMP('2025-10-19 12:00:00', 'YYYY-MM-DD HH24:MI:SS'), 140.00 FROM DUAL

),

t AS (

    SELECT 类别, 时间, 数值,

           CASE WHEN 数值 BETWEEN 100 AND 200 THEN 0 ELSE 1 END AS is_abnormal

    FROM your_data

),

grouped AS (

    SELECT 类别, 时间, 数值, is_abnormal,

           ROW_NUMBER() OVER (PARTITION BY 类别 ORDER BY 时间) -

           ROW_NUMBER() OVER (PARTITION BY 类别, is_abnormal ORDER BY 时间) AS grp

    FROM t

),

avg_abnormal AS (

    SELECT 类别, 时间, 数值, is_abnormal, grp,

           AVG(数值) OVER (PARTITION BY 类别, is_abnormal, grp) AS avg_val

    FROM grouped

)

SELECT 

    类别,

    时间,

    数值,

    CASE

        WHEN is_abnormal = 0 THEN 数值

        ELSE avg_val

    END AS 结果

FROM avg_abnormal

ORDER BY 类别, 时间

必须要排序

image.png

  • 张宇 张宇(提问者) 数据库的哪个功能?语句咋写?
    2025-10-23 11:20 
  • CD20160914 CD20160914 回复 张宇(提问者) oracel数据库的窗口函数
    2025-10-23 11:24 
  • 张宇 张宇(提问者) 回复 CD20160914 大神 怎么写?没写过
    2025-10-23 11:29 
  • CD20160914 CD20160914 回复 张宇(提问者) 你先测试楼下的mysql的写法是否可以
    2025-10-23 11:34 
  • CD20160914 CD20160914 回复 张宇(提问者) 上面是oracle的语句,我按你的截图来模拟的数据
    2025-10-23 14:11 
最佳回答
0
农夫三拳1Lv6高级互助
发布于2025-10-23 11:24
分步实现(MySQL 8.0+)步骤1:创建测试表(示例数据)
CREATE TABLE test_data (
    id INT PRIMARY KEY AUTO_INCREMENT,  -- 行号(唯一标识)
    c DECIMAL(10,2)                     -- 原始数据列);-- 插入示例数据(含正常和异常值)INSERT INTO test_data (c) VALUES(150), (250), (80), (180), (220), (230), (190), (90), (210);
步骤2:标记异常数据并分组连续异常(关键步骤)

使用 用户变量+窗口函数 实现连续异常分组(MySQL 8.0以下需用变量模拟,8.0+可直接用窗口函数):

WITH anomaly_groups AS (    SELECT 
        id,
        c,        -- 标记异常:1=异常(不在100-200),0=正常
        IF(c < 100 OR c > 200, 1, 0) AS is_anomaly,        -- 分组连续异常:正常数据触发分组值+1,异常数据继承上一分组
        SUM(IF(c BETWEEN 100 AND 200, 1, 0)) OVER (ORDER BY id) AS group_id    FROM test_data
)SELECT * FROM anomaly_groups;

分组结果示例

idcis_anomalygroup_id
1150.0001
2250.0011
380.0011
4180.0002
5220.0012
步骤3:计算组内均值并填充D列
WITH anomaly_groups AS (    -- 步骤2:标记异常并分组
    SELECT 
        id, c,
        IF(c < 100 OR c > 200, 1, 0) AS is_anomaly,        SUM(IF(c BETWEEN 100 AND 200, 1, 0)) OVER (ORDER BY id) AS group_id    FROM test_data
),
group_avg AS (    -- 计算每个异常组的均值
    SELECT 
        group_id,        AVG(c) AS anomaly_avg  -- 异常值的平均值
    FROM anomaly_groups    WHERE is_anomaly = 1  -- 仅处理异常数据
    GROUP BY group_id
)-- 关联原始表,填充D列(异常均值)SELECT 
    t.id,
    t.c,    -- 异常行显示均值,正常行D列为NULL
    CASE WHEN t.is_anomaly = 1 THEN g.anomaly_avg ELSE NULL END AS dFROM anomaly_groups tLEFT JOIN group_avg g ON t.group_id = g.group_idORDER BY t.id;
最终结果
idcd
1150.00NULL
2250.00165.00
380.00165.00
4180.00NULL
5220.00225.00
6230.00225.00

  • 3关注人数
  • 55浏览人数
  • 最后回答于:2025-10-23 14:11
    请选择关闭问题的原因
    确定 取消
    返回顶部