使用Postgres 8.4中的纪元时间获取每日最小/最大值

时间:2015-04-03 05:42:29

标签: postgresql greatest-n-per-group postgresql-8.4

我有一个带有纪元值的表(每分钟一个,纪元本身以毫秒为单位)和温度。

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,但却没有成功。

3 个答案:

答案 0 :(得分:2)

您可以从此查询开始:

SELECT  date_trunc('minute',TIMESTAMP WITH TIME ZONE 'epoch' + (time/1000) * INTERVAL '1 second') as timestamp, value AS temperature from _outdoor_temperature

显示两列,第一列是“epoch”,转换为具有“分钟”精度的时间戳。 由于您需要找到每天的最低/最高值,最好还是只有日期而不是时间戳的列:

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”表达式。这比group by更好,因为您正在查找一列的唯一值并查看另一列的关联:

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

答案 1 :(得分:1)

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

答案 2 :(得分:0)

好的,感谢@ voycheck的建议我最后添加了另一列类型为date的列,并仅使用与time字段对应的日期填充该列,因此该表看起来像这样:

 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;