在postgresql中按月和年分组查询结果

我有一个Postgres服务器上的以下数据库表:

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 

我想要创build一个查询,它给出了Sales列的SUM ,并将结果按月份和年份分组,如下所示:

 Apr 2013 3000 Toys Feb 2013 50000 Bicycle Jan 2014 4546 Bananas 

有一个简单的方法来做到这一点?

 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,将“date”属性转换为月份短格式的定义格式。

extract(year from date) as yyyy :Postgresql的“extract”函数用于从“date”属性中提取YYYY年份。

sum("Sales") as "Sales" :SUM()函数将所有“Sales”值相加,并提供区分大小写的别名,并使用双引号保持区分大小写。

group by 1,2 :GROUP BY函数必须包含SELECT列表中不属于聚集(也就是说,不在SUM / AVG / MIN / MAX等函数中的所有列)的所有列。 这告诉查询SUM()应该应用于每个唯一的列组合,在这个例子中是月份和年份列。 “1,2”部分是简写,而不是使用列别名,尽pipe为了便于阅读,最好使用完整的“to_char(…)”和“extract(…)”expression式。

我不能相信接受的答案有这么多upvotes – 这是一个可怕的方法。

以下是使用date_trunc执行此操作的正确方法:

  SELECT date_trunc('month', txn_date) AS txn_month, sum(amount) as monthly_sum FROM yourtable GROUP BY txn_month 

这是不好的做法,但如果你使用,你可能会被原谅

  GROUP BY 1 

在一个非常简单的查询。

你也可以使用

  GROUP BY date_trunc('month', txn_date) 

如果你不想selectdate。

to_char实际上可以让你一举拿下年份和月份!

 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' 

或者在上面用户的例子中:

 select to_char(date,'YY-Mon') as year_month sum("Sales") as "Sales" from some_table group by 1; 

bma答案很棒! 我用它与ActiveRecords,这是如果有人需要它在Rails中:

 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" ) 

Postgress在postgress中的时间戳几乎没有tipes:

时间戳没有时区 – (最好存储UTC时间戳)你可以在多国数据库存储中find它。 在这种情况下,客户端将处理每个国家的时区偏移量。

带时区的时间戳 – 时区的偏移量已包含在时间戳中。

在某些情况下,您的数据库不使用时区,但您仍然需要根据当地时区和夏令时(例如https://www.timeanddate.com/time/zone/romania/bucharest )对logging进行分组,

要添加时区,您可以使用此示例并用您的时区replace时区偏移量。

 "your_date_column" at time zone '+03' 

要添加特定于夏令时的+1夏令时偏移,您需要检查您的时间戳是否属于夏令时。 由于这些间隔会随着1或2天的变化而变化,所以我将使用不会影响月末logging的aproximation,因此在这种情况下,我可以忽略每年的确切时间间隔。

如果需要构build更精确的查询,则必须添加条件来创build更多的案例。 但粗略地说,当你在数据库中find没有时区的时间戳的时区和SummerTime时,

 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)