2011-08-21 51 views
4

我想是什么力量让一个表的统计信息,为此我使用generate_series();Postgres的generate_series

下面是我在做什么:

SELECT x.month, amount 
FROM (SELECT generate_series(
       min(date_trunc('month', date)), 
       max(date_trunc('month', date)), 
       '1 month' 
    ) AS month 
     FROM table 
     WHERE user_id = 55 AND ... 
) x 
LEFT JOIN (
     SELECT SUM(amount) AS amount, date_trunc('month', date) AS month 
     FROM table 
     WHERE user_id = 55 AND ... 
     GROUP BY month 
) q ON q.month = x.month 
ORDER BY month 

这种运作良好,但是当我想要应用过滤器,例如获取特定用户的金额,我必须将它们应用两次。有没有办法避免过滤两次,或以更有效的方式重写,因为我不确定这是否是正确的方法?

回答

9

你可以写WITH query此:

WITH month_amount AS 
(
    SELECT 
     sum(amount) AS amount, 
     date_trunc('month', date) AS month 
    FROM Amount 
    WHERE user_id = 55 -- AND ... 
    GROUP BY month 
) 
SELECT month, amount 
FROM 
    (SELECT generate_series(min(month), max(month), '1 month') AS month 
    FROM month_amount) x 
LEFT JOIN month_amount 
USING (month) 
ORDER BY month; 

结果举例:

SELECT * FROM amount WHERE user_id = 55; 
amount_id | user_id | amount | date  
-----------+---------+--------+------------ 
     3 |  55 |  7 | 2011-03-16 
     4 |  55 |  5 | 2011-03-22 
     5 |  55 |  2 | 2011-05-07 
     6 |  55 |  18 | 2011-05-27 
     7 |  55 |  4 | 2011-06-14 
(5 rows) 

WITH month_amount .. 
     month   | amount 
------------------------+-------- 
2011-03-01 00:00:00+01 |  12 
2011-04-01 00:00:00+02 |  
2011-05-01 00:00:00+02 |  20 
2011-06-01 00:00:00+02 |  4 
(4 rows) 
+0

我从来没有想过CTE,但他们真的很有用。非常感谢,它非常完美。 – yokoloko

+0

+1我学到了一些我对postgres不了解的东西 - 谢谢:) – Bohemian

+0

如何生成如 这样的系列从generate_series(01,12)中选择m输出:01,02,03,04,05,06,07 ,08,09,10,11,12 –

6

你可以子句中的执行您的查询,然后使用SELECT添加缺少的月份:

WITH query AS (
     SELECT SUM(amount) AS amount, date_trunc('month', date) AS month 
     FROM table 
     WHERE user_id = 55 AND ... 
     GROUP BY month 
) 
SELECT date(d.month) AS month, q.amount 
FROM (
    SELECT generate_series(min(month), max(month), '1 month') AS month 
    FROM query 
    ) d 
    LEFT JOIN query q ON q.month = d.month 
ORDER BY month