我是SQL新手,所以请原谅我.在我的一个表格中,我有一系列逆变器电压值,每分钟写一次.我正在显示GRAFANA上的数据,并希望找到异常点(如果有的话).对我来说,一个非常简单的解决方案是在特定时间获得所有电压的平均值,看看1值是否偏离了"很多".

一些背景知识:使用postresql,以及列"timestamp","value","name" name是标识符,现在反相器的格式为"INVX_INVERTER_SG_Branch VoltageY",其中Y ={1,3,5,7,9,11,13,15,17,19,21,23},X ={01—18}.

第一个临时查询按预期工作,它生成一个表,其中包含当时所有组合的时间戳和平均值.在第二个SELECT查询中,我得到的值都是废话.在DB表上没有名称包含‘SG_BRANCH电压’的其他数据.我们友好的闲聊在吐垃圾.

理想情况下,结果将显示时间戳和异常点的值.然后我将在图表上画出这些点.这将仅仅是一个指标,表明这一点并不像预期的那样.

WITH average AS (
    SELECT
        "timestamp",
        AVG(value) AS avg_value
    FROM
        st_values
    WHERE
        "timestamp" BETWEEN NOW() - INTERVAL '1 day' AND NOW() AND
        "name" LIKE 'INV%_INVERTER_SG_Branch Voltage%'
    GROUP BY "timestamp"
)
SELECT
    v."timestamp",
    v.value
FROM
    st_values v
JOIN
    average av ON av."timestamp" = v."timestamp"
WHERE
    v."timestamp" BETWEEN NOW() - INTERVAL '1 day' AND NOW() AND
    v."name" LIKE 'INV%_INVERTER_SG_Branch Voltage%' AND
    ABS(v.value - av.avg_value) / av.avg_value > 0.3 
ORDER BY
    v."timestamp";

上面的代码是(半?)没用我不知道如何调试这个.这产生了一些真正异常的点(即,躺在我的一条线上),但有些是(假的?)没有说谎

编辑:结果的截图.正如你所看到的,一些红点位于紫色(异常)线上,但是一些红点位于不应该有值的线上,

Sample data

推荐答案

您的查询中没有任何可能产生虚假值的内容.也许值得重新审视你的WHERE个条件:

  1. 如果您只想要这些来源:

    X = {01-18} and Y = {1,3,5,7,9,11,13,15,17,19,21,23}.
    

    你可以明确地表达这一点,而不是诉诸正则表达式中的catch—all %:

    "name" SIMILAR TO 
    'INV(0[1-9]|1[0-8])\_INVERTER\_SG\_Branch Voltage(1|3|5|7|9|11|13|15|17|19|21|23)' 
    ESCAPE '\'
    
    "name" ~ 
    'INV(0[1-9]|1[0-8])_INVERTER_SG_Branch Voltage(1|3|5|7|9|11|13|15|17|19|21|23)' 
    

    它对SQL标准正则表达式(SIMILAR TO)和POSIX语法(~)都很有效,除了转义部分:_下划线是LIKESIMILAR TO中的单字符分号.\反斜杠是他们的默认转义字符,所以ESCAPE '\'只是为了冗长.

    我不会怀疑你忽略了一个文本的变体,你的助手抓住了你的意图,但技术上可能是这样的.

  2. 您还可以确保您得到的意外值不在那里,因为您向表中提供的数据具有与在这里读取数据时不同的TimeZone设置.在这种情况下,

    "timestamp" BETWEEN NOW() - INTERVAL '1 day' AND NOW()`
    

    如果源在后面,可能会给你less比最后24小时的数据,或者如果源在前面4小时,你会给你4小时到28小时之间的24小时切片.如果你的"timestamp"列实际上是timestamptz,这不应该是一个问题.

  3. 您没有分享什么是"线",以及您如何准确地绘制它们,但这也可能是错误的来源.

不幸的是,如果没有一个可复制的例子,这大多只是猜测.


Window functions可以得到相同的结果,速度明显更快,代码更少:DB<>Fiddle demo

SELECT "timestamp", value FROM (
    SELECT "timestamp",
           value,
           ABS(value - avg(value)over w1) / avg(value)over w1 as deviation
    FROM st_values
    WHERE "timestamp" BETWEEN NOW() - INTERVAL '1 day' AND NOW()
      AND "name" LIKE 'INV%_INVERTER_SG_Branch Voltage%'
    WINDOW w1 AS (PARTITION BY "timestamp") ) AS subq
WHERE .3 < deviation
ORDER BY "timestamp"

由于您正在处理时间序列数据,因此可以删除索引中的default 10% empty space以加快速度.你也可以把所有感兴趣的东西都放入指数中,得到index-only scans:

create index tnv_idx on st_values ("timestamp","name")
  include("value")
  with(fillfactor=100);

如果您仍有需要运行顺序扫描的查询,这些查询可能会受益于cluster:

cluster st_values using tnv_idx;

Sql相关问答推荐

如何通过比较不同表中相同ID S的值来筛选ID为S的列表?

不可能在SQL MERGE子句中引发异常

有没有办法在每次计算每一行的数据时更新2个值?

有没有办法用SQL编写一条CASE语句,如果列A&>0,那么列B,列C=0

Oracle SQL根据列中的条件 Select 最大记录数

在数据库中搜索列

找到最新的连线

为什么我的SQL标量函数有时会抛出";子查询返回多个值.这是不允许的.

基于多参数的SQL Server条件过滤

基于是否具有某些数据的关联表覆盖SELECT语句中的列值

在PostgreSQL中汇总连接表中的 case 值

Select 一个非零值减少重复

Postgresql 生成器列导致语法错误

每次计数器增加时通过运行总重置进行分组

如何从一张表中获取值在至少三行相同的记录

使用ALTER TABLE无法删除列

所有列分组的简写?

从 varchar 列中删除特殊字符后的前面的零和字符时遇到问题

在 MS Access 中连接相关记录

如何在一个存储过程中创建全局临时表,并在另一个存储过程中使用它