在 Postgres 8.4 中使用纪元时间每天获取 min/max 值
Get min/max value per day with epoch times in Postgres 8.4
我有一个 table 具有纪元值(每分钟一个,纪元本身以毫秒为单位)和温度。
select * from outdoor_temperature order by time desc;
time | value
---------------+-------
1423385340000 | 31.6
1423385280000 | 31.6
1423385220000 | 31.7
1423385160000 | 31.7
1423385100000 | 31.7
1423385040000 | 31.8
1423384980000 | 31.8
1423384920000 | 31.8
1423384860000 | 31.8
[...]
我想获取每天发生的最低值(和最高值,但可以单独查询),以及发生的具体时间(最好是原始纪元时间)。我已经设法用 date_trunc
做到了,但这给了我一般的一天,而不是那天的具体时间:
select
date_trunc('day',TIMESTAMP WITH TIME ZONE 'epoch' + (time/1000) * INTERVAL '1 second') as timestamp,
min(value)
from outdoor_temperature
group by timestamp
order by min asc
limit 5;
timestamp | min
------------------------+------
2015-03-27 00:00:00+10 | 10.7
2015-03-28 00:00:00+10 | 10.8
2015-01-30 00:00:00+10 | 13.6
2015-03-17 00:00:00+10 | 14.0
2015-03-29 00:00:00+10 | 14.5
(5 rows)
我需要做某种加入魔法吗(我的加入魔法非常弱),还是我从完全错误的方向攻击它?我试过 DISTINCT ON
但没能成功。
您可以从这个查询开始:
SELECT date_trunc('minute',TIMESTAMP WITH TIME ZONE 'epoch' + (time/1000) * INTERVAL '1 second') as timestamp, value AS temperature from _outdoor_temperature
显示两列,第一列是 "epoch" 转换为精度为 "minute" 的时间戳。
由于您需要为每一天找到 lowest/highest 值,因此如果列也只有日期而不是时间戳,那就太好了:
SELECT
x.timestamp::date AS a,
x.timestamp AS b,
temperature AS c
FROM (
SELECT date_trunc('minute',TIMESTAMP WITH TIME ZONE 'epoch' + (time/1000) * INTERVAL '1 second') as timestamp, value AS temperature from _outdoor_temperature
) AS x
所以现在你有一个日期作为 "a" 列,一个时间戳作为 "b" 列,温度值在最后一个 "c" 列。
最后一部分是将"order by"与"distinct on"表达式结合使用。这比分组依据更好,因为您正在查找一列的唯一值并查看另一列的关联:
select distinct on(y.a)
y.a,
y.b,
y.c
from (
SELECT
x.timestamp::date AS a,
x.timestamp AS b,
temperature AS c
FROM (
SELECT date_trunc('minute',TIMESTAMP WITH TIME ZONE 'epoch' + (time/1000) * INTERVAL '1 second') as timestamp, value AS temperature from _outdoor_temperature
) AS x
) y
order by y.a, y.c
select day::date, min_value_timestamp, min_value, max_value_timestamp, max_value
from
(
select distinct on (1)
date_trunc('day', timestamp with time zone 'epoch' + time/1000 * interval '1 second') as day,
timestamp with time zone 'epoch' + (time/1000 * interval '1 second') as min_value_timestamp,
value as min_value
from outdoor_temperature
order by 1, 3
) s
inner join
(
select distinct on (1)
date_trunc('day', timestamp with time zone 'epoch' + time/1000 * interval '1 second') as day,
timestamp with time zone 'epoch' + (time/1000 * interval '1 second') as max_value_timestamp,
value as max_value
from outdoor_temperature
order by 1, 3 desc
) v using (day)
order by 1
好的,感谢@voycheck 的建议,我最终添加了另一列 date
类型,并仅使用对应于 time
字段的日期填充它,因此 table看起来像这样:
Column | Type | Modifiers
--------+---------+-----------
time | bigint | not null
value | numeric |
date | date |
Indexes:
"outdoor_temperature_pkey" PRIMARY KEY, btree ("time")
"outdoor_temperature_date_idx" btree (date)
"outdoor_temperature_value_idx" btree (value)
然后大大简化并加快了 SQL 查询:
SELECT time, value FROM (
SELECT DISTINCT ON (date)
date, time, value
FROM outdoor_temperature
ORDER BY date, value desc
) t
ORDER BY t.value desc;
我有一个 table 具有纪元值(每分钟一个,纪元本身以毫秒为单位)和温度。
select * from outdoor_temperature order by time desc;
time | value
---------------+-------
1423385340000 | 31.6
1423385280000 | 31.6
1423385220000 | 31.7
1423385160000 | 31.7
1423385100000 | 31.7
1423385040000 | 31.8
1423384980000 | 31.8
1423384920000 | 31.8
1423384860000 | 31.8
[...]
我想获取每天发生的最低值(和最高值,但可以单独查询),以及发生的具体时间(最好是原始纪元时间)。我已经设法用 date_trunc
做到了,但这给了我一般的一天,而不是那天的具体时间:
select
date_trunc('day',TIMESTAMP WITH TIME ZONE 'epoch' + (time/1000) * INTERVAL '1 second') as timestamp,
min(value)
from outdoor_temperature
group by timestamp
order by min asc
limit 5;
timestamp | min
------------------------+------
2015-03-27 00:00:00+10 | 10.7
2015-03-28 00:00:00+10 | 10.8
2015-01-30 00:00:00+10 | 13.6
2015-03-17 00:00:00+10 | 14.0
2015-03-29 00:00:00+10 | 14.5
(5 rows)
我需要做某种加入魔法吗(我的加入魔法非常弱),还是我从完全错误的方向攻击它?我试过 DISTINCT ON
但没能成功。
您可以从这个查询开始:
SELECT date_trunc('minute',TIMESTAMP WITH TIME ZONE 'epoch' + (time/1000) * INTERVAL '1 second') as timestamp, value AS temperature from _outdoor_temperature
显示两列,第一列是 "epoch" 转换为精度为 "minute" 的时间戳。 由于您需要为每一天找到 lowest/highest 值,因此如果列也只有日期而不是时间戳,那就太好了:
SELECT
x.timestamp::date AS a,
x.timestamp AS b,
temperature AS c
FROM (
SELECT date_trunc('minute',TIMESTAMP WITH TIME ZONE 'epoch' + (time/1000) * INTERVAL '1 second') as timestamp, value AS temperature from _outdoor_temperature
) AS x
所以现在你有一个日期作为 "a" 列,一个时间戳作为 "b" 列,温度值在最后一个 "c" 列。
最后一部分是将"order by"与"distinct on"表达式结合使用。这比分组依据更好,因为您正在查找一列的唯一值并查看另一列的关联:
select distinct on(y.a)
y.a,
y.b,
y.c
from (
SELECT
x.timestamp::date AS a,
x.timestamp AS b,
temperature AS c
FROM (
SELECT date_trunc('minute',TIMESTAMP WITH TIME ZONE 'epoch' + (time/1000) * INTERVAL '1 second') as timestamp, value AS temperature from _outdoor_temperature
) AS x
) y
order by y.a, y.c
select day::date, min_value_timestamp, min_value, max_value_timestamp, max_value
from
(
select distinct on (1)
date_trunc('day', timestamp with time zone 'epoch' + time/1000 * interval '1 second') as day,
timestamp with time zone 'epoch' + (time/1000 * interval '1 second') as min_value_timestamp,
value as min_value
from outdoor_temperature
order by 1, 3
) s
inner join
(
select distinct on (1)
date_trunc('day', timestamp with time zone 'epoch' + time/1000 * interval '1 second') as day,
timestamp with time zone 'epoch' + (time/1000 * interval '1 second') as max_value_timestamp,
value as max_value
from outdoor_temperature
order by 1, 3 desc
) v using (day)
order by 1
好的,感谢@voycheck 的建议,我最终添加了另一列 date
类型,并仅使用对应于 time
字段的日期填充它,因此 table看起来像这样:
Column | Type | Modifiers
--------+---------+-----------
time | bigint | not null
value | numeric |
date | date |
Indexes:
"outdoor_temperature_pkey" PRIMARY KEY, btree ("time")
"outdoor_temperature_date_idx" btree (date)
"outdoor_temperature_value_idx" btree (value)
然后大大简化并加快了 SQL 查询:
SELECT time, value FROM (
SELECT DISTINCT ON (date)
date, time, value
FROM outdoor_temperature
ORDER BY date, value desc
) t
ORDER BY t.value desc;