如何在MySQL中按周分组?

时间:2009-11-14 23:43:51

标签: mysql datetime group-by data-migration dayofweek

Oracle的表服务器提供内置函数TRUNC(timestamp,'DY')。此函数将上一个星期日的任何时间戳转换为午夜。在MySQL中执行此操作的最佳方法是什么?

Oracle还提供TRUNC(timestamp,'MM')将时间戳转换为发生月份的第一天的午夜。在MySQL中,这个很简单:

TIMESTAMP(DATE_FORMAT(timestamp, '%Y-%m-01'))

但这个DATE_FORMAT技巧几周不会奏效。我知道WEEK(timestamp)函数,但我真的不想要一年中的周数;这个东西是多年的工作。

8 个答案:

答案 0 :(得分:98)

您可以同时使用YEAR(timestamp)WEEK(timestamp),并在SELECTGROUP BY子句中使用这两个表达式。

不是太优雅,但功能性......

当然,您也可以将这两个日期部分组合在一个表达式中,例如

SELECT CONCAT(YEAR(timestamp), '/', WEEK(timestamp)), etc...
FROM ...
WHERE ..
GROUP BY CONCAT(YEAR(timestamp), '/', WEEK(timestamp))

编辑:正如Martin xx指出的那样,你也可以使用YEARWEEK(mysqldatefield)函数,虽然它的输出不如上面较长的公式那样友好。

编辑2 [3年半以后!]:
YEARWEEK(mysqldatefield)将可选的第二个参数(mode)设置为0或2可能是完整周聚合的最佳方式(即包括跨越1月1日的几周) ),如果那是你想要的。最初在这个答案中提出的YEAR() / WEEK()方法将这种“跨越”周的汇总数据分成两部分:一年与前一年,一年与新年相同。
每年都要做一个简洁的工作,最多需要两个部分周,一个是两端,通常需要会计等等。YEAR() / WEEK()方法更好。

答案 1 :(得分:25)

上面接受的答案对我不起作用,因为它按字母顺序排序了几周,而不是按时间顺序排列:

2012/1
2012/10
2012/11
...
2012/19
2012/2

这是我按周计算和分组的解决方案:

SELECT CONCAT(YEAR(date), '/', WEEK(date)) AS week_name, 
       YEAR(date), WEEK(date), COUNT(*)
FROM column_name
GROUP BY week_name
ORDER BY YEAR(DATE) ASC, WEEK(date) ASC

生成:

YEAR/WEEK   YEAR   WEEK   COUNT
2011/51     2011    51      15
2011/52     2011    52      14
2012/1      2012    1       20
2012/2      2012    2       14
2012/3      2012    3       19
2012/4      2012    4       19

答案 2 :(得分:23)

想出来......这有点麻烦,但现在就是。

FROM_DAYS(TO_DAYS(TIMESTAMP) -MOD(TO_DAYS(TIMESTAMP) -1, 7))

而且,如果您的商家规则规定您的周数从周一开始,请将-1更改为-2


修改

几年过去了,我终于开始写这篇文章了。 http://www.plumislandmedia.net/mysql/sql-reporting-time-intervals/

答案 3 :(得分:21)

您可以使用YEARWEEK()功能获取连锁的年份和周数(200945)。如果我正确理解您的目标,那么您应该可以对多年数据进行分组。

如果您需要本周开始时的实际时间戳,那就不太好了:

DATE_SUB( field, INTERVAL DAYOFWEEK( field ) - 1 DAY )

对于每月订购,您可能会考虑LAST_DAY()功能 - 排序将在该月的最后一天进行,但这相当于按月的第一天排序...不应该吗?< / p>

答案 4 :(得分:4)

只需在选择中添加:

DATE_FORMAT($yourDate, \'%X %V\') as week

并且

group_by(week);

答案 5 :(得分:2)

如果您需要“周结束”日期,这也可以。这将计算每周的记录数。示例:如果在(包括)1/2/2010和1/8/2010之间创建了三个工作订单,并且在(包括)2010年1月9日和2010年1月16日之间创建了5个工作订单,则返回:

3 1/8/2010
5 1/16/2010

我不得不使用额外的DATE()函数来截断我的日期时间字段。

SELECT COUNT(*), DATE_ADD( DATE(wo.date_created), INTERVAL (7 - DAYOFWEEK( wo.date_created )) DAY) week_ending FROM work_order wo GROUP BY week_ending;

答案 6 :(得分:0)

我喜欢 MySQL 中的 week 函数,但在我的情况下,我想知道一行在一个月的哪一周。我使用了这个解决方案:

其中 run_date 是一个时间戳,如 2021-02-25 00:00:00

concat ( 
        date_format(run_date, '%Y-%m'), 
        ' wk ', 
        (week(run_date,1) - ( week(date_format(run_date, '%Y-%m-01')) - 1))
        ) as formatted_date

输出:

2021-02-23 --->    2021-02 wk 4
2021-02-25 --->    2021-02 wk 4
2021-02-11 --->    2021-02 wk 2
2021-03-02 --->    2021-03 wk 1

这背后的想法是我想(相对确定地)知道该日期发生在月份的哪一周

所以我们连接:

date_format(run_date, '%Y-%m') 得到 2021-02

然后我们添加文字字符串wk

然后我们使用: week(run_date, 1) 获取此记录的周(1 开始星期一),(这将是 7,因为 02/21/2021 是在一年的第 7 周,我们减去无论该月的第 1 天是哪一周 - week()2021-02-01 是 5,因为它在一年中的第 5 周:

(week(date_format(run_date, '%Y-%m-01'))

不幸的是,这会从 0 开始计数,这是人们不喜欢的,所以我们从串联结果的最后一部分减去 1,这样“周”从 1 开始。

答案 7 :(得分:0)

这可能是一个不错的选择:

SELECT
 year(datetime_field) as year_date, week(datetime_field) as week_date
FROM
 bd.table
GROUP BY
 year_date, week_date;

它看起来像这样:

  • '2020'、'14'
  • '2020'、'15'
  • '2020'、'16'
  • '2020'、'17'
  • '2020'、'18'