2015-11-19 88 views
4

我有點麻煩的數字這一個。有條件地按日期分組

我有兩個表itemsstocks

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 

我四處搜尋,發現一些所謂的日期部分,但它似乎並不像我所需要的。

+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 joingenerate_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

感謝,這個效果很好,我與Clodo阿爾的答案會因爲它的短 – lusketeer

+0

@lusketeer。 。 。我不確定它在較大的數據上表現如何,但在較小的數據集上應該沒問題。 –

+0

數據集目前很小,我會在db增長時記住你的答案。謝謝,感謝! – lusketeer