关于sql:在postgresql中按月和年分组查询结果

Group query results by month and year in postgresql

我在Postgres服务器上有以下数据库表:

1
2
3
4
5
id      DATE          Product Sales
1245    01/04/2013    Toys    1000    
1245    01/04/2013    Toys    2000
1231    01/02/2013    Bicycle 50000
456461  01/01/2014    Bananas 4546

我想创建一个查询,给出Sales列的SUM,并按月份和年份对结果进行分组,如下所示:

1
2
3
Apr    2013    3000     Toys
Feb    2013    50000    Bicycle
Jan    2014    4546     Bananas

有简单的方法吗?


我不能相信有这么多的答案upvotes接受——这是一个挺吓人的方法。

这是做它的方式correct,与_ trunc日期:

1
2
3
   SELECT date_trunc('month', txn_date) AS txn_month, SUM(amount) AS monthly_sum
     FROM yourtable
 GROUP BY txn_month

这是不好的做法,但你可能forgiven如果你使用

1
 GROUP BY 1

在一个非常简单的查询。

你可以同时使用

1
 GROUP BY date_trunc('month', txn_date)

如果你不想选择的日期。


1
2
3
4
5
SELECT to_char(DATE,'Mon') AS mon,
       EXTRACT(YEAR FROM DATE) AS yyyy,
       SUM("Sales") AS"Sales"
FROM yourtable
GROUP BY 1,2

在请求的Radu,我不能解释,将查询:

to_char(date,'Mon') as mon,:converts进入"日期"格式的定义attribute月短形式。

extract(year from date) as yyyy:postgresql的"extract"的功能是用来extract的yyyy attribute年从"日期"。

sum("Sales") as"Sales"顺():所有功能都增加了"销售"的价值观,和supplies -敏感的一个案例与alias情况,由使用的双quotes保持敏感性。

group by 1,2:由功能组包含所有列必须从选择列表,是不是部分aggregate(又名顺列,所有不在/ etc / avg Min / Max当日)。这告诉顺()的查询,应该是独特的组合应用对每一列,其中在这种情况下,是月和年的列。"120"部分是一个shorthand aliases柱而不是使用最大的努力,虽然这是可能使用的完整的"大_ char(……)"和"extract expressions为readability(…)"。


to_char实际上让你拉出来的年和月swoop在一了!

1
2
SELECT to_char(DATE('2014-05-10'),'Mon-YY') AS year_month; --'May-14'
SELECT to_char(DATE('2014-05-10'),'YYYY-MM') AS year_month; --'2014-05'

在的情况下的用户,或以上的例子:

1
2
3
4
SELECT to_char(DATE,'YY-Mon') AS year_month
       SUM("Sales") AS"Sales"
FROM some_table
GROUP BY 1;


有另一种方式以实现的结果使用日期_部分在postgres()函数。

1
2
3
 SELECT date_part('month', txn_date) AS txn_month, date_part('year', txn_date) AS txn_year, SUM(amount) AS monthly_sum
     FROM yourtable
 GROUP BY date_part('month', txn_date)

谢谢你


bma回答是伟大的!我已经用它与activerecords,在这里它是:如果有人需要它在rails

1
2
3
4
5
6
7
8
Model.find_by_sql(
 "SELECT TO_CHAR(created_at, 'Mon') AS month,
   EXTRACT(year from created_at) as year,
   SUM(desired_value) as desired_value
   FROM desired_table
   GROUP BY 1,2
   ORDER BY 1,2"

)


有一些类型的timestamps:postgres

timestamp无timezone -(preferable大商店timestamps GMT)你找到它在multinational数据库存储。在这种情况下的client会照顾的timezone粒状为每个国家。

timestamp与timezone - timezone粒状是已经包括在timestamp。

在一些情况下,你的数据库使用的timezone不做,但你仍然需要记录在本地组的老学校的武器与saving timezone和日光时间(例如HTTPS www.timeanddate.com /:/ / / / /罗马尼亚布加勒斯特Time Zone)

你可以添加大timezone使用这个例子和取代的timezone粒状与你。

1
"your_date_column" at TIME zone '+03'

添加一个夏天的时间大大+粒状dst具体你需要检查如果你的timestamp dst落在一个夏天。作为这些变化的intervals与一或两天,我会使用不安全的aproximation,并不影响最后的月记录,所以在这种情况下,我可以忽略每年interval准确。

如果更多的precise查询已成为建立,然后你必须添加更大的情况下,创造了条件。但大约在splitting罚款,这将工作数据,每月在老学校的武器与timezone和夏季,当你发现在你的timestamp无timezone数据库:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
SELECT
   "id","Product","Sale",
    date_trunc('month',
        CASE WHEN
            EXTRACT(MONTH FROM t."date") > 03 AND
            EXTRACT(DAY FROM t."date") > 26 AND
            EXTRACT(HOUR FROM t."date") > 3 AND
            EXTRACT(MONTH FROM t."date") < 10 AND
            EXTRACT(DAY FROM t."date") < 29 AND
            EXTRACT(HOUR FROM t."date") < 4
        THEN
            t."date" at TIME zone '+03' -- Romania TimeZone offset + DST
        ELSE
            t."date" at TIME zone '+02' -- Romania TimeZone offset
        END) AS"date"
FROM
    public."Table" AS t
WHERE 1=1
    AND t."date">= '01/07/2015 00:00:00'::TIMESTAMP WITHOUT TIME ZONE
    AND t."date" < '01/07/2017 00:00:00'::TIMESTAMP WITHOUT TIME ZONE
GROUP BY date_trunc('month',
    CASE WHEN
        EXTRACT(MONTH FROM t."date") > 03 AND
        EXTRACT(DAY FROM t."date") > 26 AND
        EXTRACT(HOUR FROM t."date") > 3 AND
        EXTRACT(MONTH FROM t."date") < 10 AND
        EXTRACT(DAY FROM t."date") < 29 AND
        EXTRACT(HOUR FROM t."date") < 4
    THEN
        t."date" at TIME zone '+03' -- Romania TimeZone offset + DST
    ELSE
        t."date" at TIME zone '+02' -- Romania TimeZone offset
    END)