如何在MySQL中按周分组?

如何在MySQL中按周分组?,mysql,datetime,group-by,data-migration,dayofweek,Mysql,Datetime,Group By,Data Migration,Dayofweek,Oracle的table server提供了一个内置函数,TRUNC(timestamp,'DY')。此函数用于将任何时间戳转换为前一个星期日的午夜。在MySQL中实现这一点的最佳方法是什么 Oracle还提供了TRUNC(timestamp,'MM')将时间戳转换为发生时间的月份第一天的午夜。在MySQL中,这一点很简单: TIMESTAMP(DATE_FORMAT(timestamp, '%Y-%m-01')) 但是这种DATE\u格式的技巧在几周内都不会奏效。我知道WEEK(timest

Oracle的table server提供了一个内置函数,
TRUNC(timestamp,'DY')
。此函数用于将任何时间戳转换为前一个星期日的午夜。在MySQL中实现这一点的最佳方法是什么

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

TIMESTAMP(DATE_FORMAT(timestamp, '%Y-%m-01'))
但是这种
DATE\u格式的技巧在几周内都不会奏效。我知道
WEEK(timestamp)
函数,但我真的不想要一年内的周数;这些东西是用于多年工作的。

您可以同时使用and,并在
SELECT
groupby
子句中使用这两个表达式

不太优雅,但功能性强

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

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

编辑:正如Martin所说,您也可以使用该函数,尽管其输出不像上面较长的公式那样直观


编辑2[3年半后!]:
如果需要的话,将可选的第二个参数()设置为0或2可能是按完整周(即包括跨越1月1日的周)进行聚合的最佳方式。本回答中最初提出的
YEAR()/WEEK()
方法的效果是将此类“跨越”周的汇总数据分为两部分:一部分是前一年,另一部分是新的一年。

在会计等方面,通常需要每年进行一次清理,但代价是最多有两个不完整的周,两端各有一个。因此,
year()/WEEK()
方法更好。

您可以使用该函数获得串联的年和周数(200945)。如果我正确理解了您的目标,那么您就可以对多年数据进行分组

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

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

对于每月排序,您可以考虑函数排序将在月底的最后一天,但这应该相当于按月份的第一天排序。不应该吗?

算出了。。。有点笨重,但在这里

FROM_DAYS(TO_DAYS(TIMESTAMP) -MOD(TO_DAYS(TIMESTAMP) -1, 7))
而且,如果您的业务规则规定您的工作周从周一开始,请将
-1
更改为
-2


编辑

几年过去了,我终于开始写这篇文章了。

只需在选择中添加此项:

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

如果你需要“周末”日期,这也可以。这将统计每周的记录数。示例:如果在2010年1月2日和2010年1月8日之间创建了三个工单,并且在2010年1月9日和2010年1月16日之间创建了五个工单,则返回:

3 2010年1月8日
5 2010年1月16日

我必须使用额外的DATE()函数来截断我的datetime字段

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;

上述被接受的答案对我来说并不适用,因为它是按字母顺序排列的,而不是按时间顺序排列的:

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

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

其中
run\u 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\u格式(运行日期,%Y-%m')
获取
2021-02

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

然后我们使用:
week(run\u date,1)
获取此记录的周(
1
从周一开始),这将是
7
,因为2021年2月21日是一年中的第7周,我们减去本月第一天的周数-周(
week)
2021-02-01
的值为5,因为这是一年中的第5周:

(星期(日期格式(运行日期,%Y-%m-01))


不幸的是,这将开始计数0,这是人们不喜欢的,所以我们从连接结果的最后部分减去1,使得“星期”开始在1。< /p> +1马丁。对我来说,我忘记了一年的时间……我只是不太使用它。为了提高可读性。马丁,我考虑过这一点,发现这些函数在星期一到星期天运行0-6。我的业务规则说星期天从00:00开始,所以工作日的内容有点难看。关于可读性,你说得对。@OllieJones完美!非常感谢!非常好的解决方案和文章。谢谢!有一种方法可以设置“星期一”第一天?你是指trunc(sysdate,'W'),而不是trunc(sysdate,'DY')
trunc(date,'DY')
星期天开始。
'W'
星期一开始,至少在我的系统中是这样。
YEARWEEK()
导致
INT(6)
我相信这会更快地排序/加入/分组with@mjv:当两年共享同一周时会发生什么情况?比如2012年12月31日到2013年1月6日(周一到周日)。有什么解决办法吗?@hardik:请参见编辑2。根据个人需要,YEARWEEK()如果您希望使用完整的周而不是拆分一年中的最后/第一个部分周,那么这可能是一个更好的聚合键。@mjv这里有另一个解决方案,确保“timestamp”不是一个整数,就像我在表中所做的那样。week(timestamp)将date/timestamp列类型作为有效的参数按日期排序(
按日期订购ASC
)应该可以做到这一点too@Fender如果表设置为仅允许group by的严格列,则无法按顺序执行“日期”(日期不在group by YEAR中,星期版本为),这是MYSQLhow上的默认设置,它不会连续获取数据,而只获取一个特定日期的数据
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