Postgres查询当天最新记录和第一条记录之间的差异

Postgres query for difference between latest and first record of the day

类似这样的 Postgres 数据:

|   id  |         read_at        | value_1 |
| ------|------------------------|---------|
| 16239 | 2021-11-28 16:13:00+00 |   1509  |
| 16238 | 2021-11-28 16:12:00+00 |   1506  |
| 16237 | 2021-11-28 16:11:00+00 |   1505  |
| 16236 | 2021-11-28 16:10:00+00 |   1501  |
| 16235 | 2021-11-28 16:09:00+00 |   1501  |
| ..... | .......................|   ....  |
| 15266 | 2021-11-28 00:00:00+00 |   1288  |

每分钟增加一个值,并随时间增加。

我想获取当天的当前总数并将其显示在 Grafana 统计面板中。上面是:221 (1509-1288)。最新记录减去今天的第一条记录。

SELECT id,read_at,value_1
FROM xyz
ORDER BY id DESC
LIMIT 1;

由此给出最新记录(A)。

SELECT id,read_at,value_1
FROM xyz
WHERE read_at = CURRENT_DATE
ORDER BY id DESC
LIMIT 1;

这样就给出了当天的第一条记录 (B)。

Grafana 无法对此 (A-B) 进行数学运算。单个查询最好。

遗憾的是,我的数据库知识不多,构建查询的尝试没有成功,现在已经花了整个下午。

解决这个问题的理论思路:

前进的最佳方式(性能方面)是什么?如何编写此类查询?

使用 window 函数(这是 t 子查询)计算当天每条记录的累计总数 last_value - first_value,然后选择最新的。

select current_total, read_at::date as read_at_date 
from
(
  select last_value(value_1) over w - first_value(value_1) over w as current_total,
         read_at 
  from the_table
  where read_at >= current_date and read_at < current_date + 1
  window w as (partition by read_at::date order by read_at)
) as t
order by read_at desc limit 1;

但是,如果确定 value_1 只是“随时间增加”,那么简单的分组就可以了,这是迄今为止性能最好的方法:

select max(value_1) - min(value_1) as current_total, 
       read_at::date as read_at_date 
from the_table
where read_at >= current_date and read_at < current_date + 1
group by read_at::date;

请检查它是否有效。

由于您打算在 Grafana 中发布它,因此查询不会强加句点过滤器。

https://www.db-fiddle.com/f/4jyoMCicNSZpjMt4jFYoz5/3080

create table g (id int, read_at timestamp, value_1 int);

insert into g
values
(16239, '2021-11-28 16:13:00+00', 1509),
(16238, '2021-11-28 16:12:00+00', 1506),
(16237, '2021-11-28 16:11:00+00', 1505),
(16236, '2021-11-28 16:10:00+00', 1501),
(16235, '2021-11-28 16:09:00+00', 1501),
(15266, '2021-11-28 00:00:00+00', 1288);

select date(read_at), max(value_1) - min(value_1)
from g
group by date(read_at);

由于您的数据包含 2 个不同时间(16:09 和 16:10)的多个值,这表明最小值和最大值可能并不总是在时间间隔内增加。保留减少的可能性。那么你想要最大 - 最小读数还是 min/max 时间的读数差异。下面get value difference 获取当日首读和最新读的差值,如题所示。

with parm(dt) as 
     ( values (date '2021-11-28') )
   , first_read (f_read,f_value) as 
     ( select read_at, value_1 
         from test_tbl
        where read_at at time zone 'UTC'= 
                   ( select min(read_at at time zone 'UTC') 
                            from test_tbl
                            join parm  
                              on ((read_at at time zone 'UTC')::date = dt) 
                        )
     ) 
   , last_read (l_read, l_value) as 
     ( select read_at,value_1 
         from test_tbl
        where read_at at time zone 'UTC'= 
                     ( select max(read_at at time zone 'UTC') 
                            from test_tbl
                            join parm  
                              on ((read_at at time zone 'UTC')::date = dt) 
                        )
     ) 
select l_read, f_read, l_value, f_value, l_value - f_value as "Day Difference"
 from last_read 
 join first_read on true;