2016-08-05 5 views
0

У меня есть таблица с датой и несколькими значениями, которые я группирую и некоторые из которых я агрегирую, запрос будет как получить доход от клиента на прошлой неделе. Теперь я хочу увидеть изменение между запрошенным периодом и предыдущим, так что у меня будет 2 столбца дохода и previous_revenue.Агрегированные значения в зависимости от другого поля

Прямо сейчас я запрашиваю строки запрошенного периода плюс строки предыдущего периода, и для каждого агрегированного поля я добавляю оператор case, внутри которого возвращают значение или 0, если не в том периоде, который я хочу.

Это приводит к тому, что столько CASE, как агрегированные поля, но всегда с тем же условным выражением.

мне интересно, если есть лучший дизайн для этого случая использования ...

SELECT 
customer, 
SUM(
    CASE TIMESTAMP_CMP('2016-07-01 00:00:00', ft.date) > 0 WHEN true THEN 
    REVENUE 
    ELSE 0 END 
) AS revenue, 
SUM(
    CASE TIMESTAMP_CMP('2016-07-01 00:00:00', ft.date) < 0 WHEN true THEN 
    REVENUE 
    ELSE 0 END 
) AS previous_revenue 

WHERE date_hour >= '2016-06-01 00:00:00' 
AND date_hour <= '2016-07-31 23:59:59' 
GROUP BY customer 

(В моем реальном случае использования у меня есть много столбцов, которые делают его еще более некрасиво)

ответ

0

Первых , Я бы предложил реорганизовать временные метки и предварительно рассчитать текущий и предыдущий период для последующего использования. Это не является строго необходимым, чтобы решить вашу проблему, хотя:

create temporary table _period as 
    select 
     '2016-07-01 00:00:00'::timestamp as curr_period_start 
     , '2016-07-31 23:59:59'::timestamp as curr_period_end 
     , '2016-06-01 00:00:00'::timestamp as prev_period_start 
     , '2016-06-30 23:59:59'::timestamp as prev_period_end 
; 

Теперь можно дизайн, чтобы избежать повторения меток времени и CASE заявления состоит в группе по периодам первого, а затем делать FULL OUTER JOIN для этой таблицы на себе:

with _aggregate as (
    select 
     case 
      when date_hour between prev_period_start and prev_period_end then 'previous' 
      when date_hour between curr_period_start and curr_period_end then 'current' 
     end::varchar(20) as period 
     , customer 
    -- < other columns to group by go here > 
     , sum(revenue)  as revenue 
    -- < other aggregates go here > 
    from 
     _revenue, _period 
    where 
     date_hour between prev_period_start and curr_period_end 
    group by 1, 2 
) 
select 
    customer 
    , current_period.revenue as revenue 
    , previous_period.revenue as previous_revenue 
from 
       (select * from _aggregate where period = 'previous') previous_period 
full outer join (select * from _aggregate where period = 'current') current_period 

using(customer) -- All columns which have been group by must go into the using() clause: 
       -- e.g. using(customer, some_column, another_column) 
; 
Смежные вопросы