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 函数。
前进的最佳方式(性能方面)是什么?如何编写此类查询?
使用 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;
类似这样的 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 函数。
前进的最佳方式(性能方面)是什么?如何编写此类查询?
使用 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;