在 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;