2015-11-19 3 views
4

У меня возникли проблемы с этим.Условная группировка по дате

У меня есть две таблицы items и stocks

items 
id | name 
1 | item_1  
2 | item_2  

stocks 
id | item_id | quantity | expired_on 
1 | 1 | 5  | 2015-11-12 
2 | 1 | 5  | 2015-11-13 
3 | 2 | 5  | 2015-11-12 
4 | 2 | 5  | 2015-11-14 

Я хочу, чтобы иметь возможность получить большую таблицу, сгруппированные по дате, и по каждой дате, группы по item_id и показать сумму количества, не истек ,

result 
date  | item_id | unexpired 
2015-11-11 | 1 | 10  
2015-11-11 | 2 | 10  
2015-11-12 | 1 | 5  
2015-11-12 | 2 | 5  
2015-11-13 | 1 | 0  
2015-11-13 | 2 | 5  
2015-11-14 | 1 | 0  
2015-11-14 | 2 | 0 

Я могу получить результат, если это только один день

SELECT 
    items.id, SUM(stocks.quantity) as unexpired 
FROM 
    items LEFT OUTER JOIN stocks 
    ON items.id = stocks.item_id 
WHERE 
    stocks.expired_on > '2015-11-11' 
GROUP BY 
    items.id, stocks.quantity 

Я искал вокруг, нашел то, что называется DatePart, но это не похоже, что мне нужно.

+0

Является 'LEFT OUTER JOINS' действительно вещь в PostgreSQL, или что плюрализация опечатка? – LDMJoe

+0

sry, это опечатка – lusketeer

ответ

5

Используя удобный бросок из boolean к integer, что дает 0, 1 или нуль, чтобы подвести остающийся только

select 
    to_char(d, 'YYYY-MM-DD') as date, 
    item_id, 
    sum(quantity * (expired_on > d)::int) as unexpired 
from 
    stocks 
    cross join 
    generate_series(
     '2015-11-11'::date, '2015-11-14', '1 day' 
    ) d(d) 
group by 1, 2 
order by 1, 2 
; 
    date | item_id | unexpired 
------------+---------+----------- 
2015-11-11 |  1 |  10 
2015-11-11 |  2 |  10 
2015-11-12 |  1 |   5 
2015-11-12 |  2 |   5 
2015-11-13 |  1 |   0 
2015-11-13 |  2 |   5 
2015-11-14 |  1 |   0 
2015-11-14 |  2 |   0 

cross join к generate_series поставляет все даты в заданном диапазоне.

Данные использованные выше:

create table stocks (
    id int, 
    item_id int, 
    quantity int, 
    expired_on date 
); 
insert into stocks (id,item_id,quantity,expired_on) values 
(1,1,5,'2015-11-12'), 
(2,1,5,'2015-11-13'), 
(3,2,5,'2015-11-12'), 
(4,2,5,'2015-11-14'); 
+0

спасибо! это отлично работает! – lusketeer

1

Вам необходимо сгенерировать список дат, а затем использовать перекрестное соединение, чтобы получить полные комбинации дат и предметов. Затем left join в таблицу запаса дает срок действия истек в каждой дате. Совокупная сумма - в обратном направлении - рассчитывается unexpired:

select d.dte, i.item_id, 
     sum(quantity) over (partition by i.item_id 
          order by d.dte desc 
          rows between unbounded preceding and 1 preceding 
         ) as unexpired 
from (select generate_series(min(expired_on) - interval '1 day', max(expired_on), interval '1 day') as dte 
     from stocks 
    ) d cross join 
     items i left join 
     stocks s 
     on d.dte = s.expired_on and i.item_id = s.item_id; 
+0

спасибо, этот хорошо работает, я иду с ответом клодоальдо, так как он короче – lusketeer

+0

@lusketeer. , , Я не уверен, что он будет работать и на больших данных, но на небольших наборах данных это должно быть хорошо. –

+0

набор данных в настоящее время невелик, я буду учитывать ваш ответ, поскольку db растет. Спасибо, оцените! – lusketeer

Смежные вопросы