使用翻转确定差值

时间:2014-09-26 22:07:28

标签: sql postgresql postgresql-9.3

我有下表:

 id | location_id | datetime            | value1 | value2 
 ---------------------------------------------------------
  1 |         123 | 2014-09-01 00:00:00 |  10000 |   5000
  2 |         123 | 2014-09-01 00:05:00 |  15000 |  10000
  3 |         123 | 2014-09-01 00:10:00 |  20000 |  15000
  4 |         123 | 2014-09-01 00:15:00 |  25000 |  20000
  5 |         123 | 2014-09-01 00:20:00 |   5000 |   1000
  6 |         123 | 2014-09-01 00:25:00 |  10000 |   5000
                   .....
 99 |         123 | 2014-09-01 23:55:00 |  90000 |  30000
100 |         123 | 2014-09-02 00:00:00 |  95000 |  35000
  x |         123 | 2014-09-02 00:05:00 | 100000 |  40000
                   .....
  x |         999 | 2014-09-01 00:00:00 |  50000 |  30000
  x |         999 | 2014-09-01 00:05:00 |  55000 |  35000

对于给定的location_id,值列将始终增加,除非发生翻转(在这种情况下,值再次从零开始)

对于数百个不同的location_ids,此表每5分钟会有一行。 请注意,从ID 5开始的值列中存在翻转。

我希望在给定一组日期(ex / 2014-08-01 - 2014-09-01)的情况下,为每个location_id获取每天值列的差异。

要在2014-09-01日期获取location_id 123的所需值,我需要考虑翻转。它将(使用value1作为示例):

90000 (row id 99 - ending value) + 25000 (row id 4 - rollover value) - 10000 (row id 1 - starting value) = 105000

结果看起来像这样:

location_id | date       | value1 | value2
------------------------------------------
        123 | 2014-09-01 | 105000 |  45000
        123 | 2014-09-02 |  90000 |  50000
        123 | 2014-09-03 |  70000 |  35000
        999 | 2014-09-01 | 100000 |  90000
        999 | 2014-09-02 |  80000 |  60000
        999 | 2014-09-03 |  70000 |  50000

对于查询中指定的每个日期,此结果将显示每个location_id的每日差异。

关于如何攻击这个的任何想法?

1 个答案:

答案 0 :(得分:1)

我假设翻转后的值总是更少。

此查询使用row_number按日期对值进行编号,并使用条件聚合来添加或减去last,first和rollover值。

select
    location_id,
    date(datetime) date,
    sum(case 
        when rn_datetime_desc = 1 then value1 
        when rn_datetime_asc = 1 then (value1 * -1)
        when next_value1 < value1 then value1
        else 0 
        end) value1
from  (
    select 
        location_id, datetime, value1
        lead(value1) over (partition by date(datetime) order by datetime asc) next_value1,
        row_number() over (partition by date(datetime) order by datetime asc) rn_datetime_asc,
        row_number() over (partition by date(datetime) order by datetime desc) rn_datetime_desc
    from mytable order by datetime asc
) t1
group by location_id, date(datetime)