109

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

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

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

但是这个DATE_FORMAT技巧在几周内都行不通。我知道这个WEEK(timestamp)功能,但我真的不想要一年内的周数;这东西适合多年工作。

4

9 回答 9

141

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

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

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

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

编辑:正如 Martin指出的那样,您也可以使用该YEARWEEK(mysqldatefield)功能,尽管它的输出不如上面较长的公式那么眼睛友好。


编辑 2 [3 1/2 年后!]:
YEARWEEK(mysqldatefield)将可选的第二个参数 ( ) 设置为 0 或 2 可能是按完整mode周聚合的最佳方式(即包括跨越 1 月 1 日的几周),如果这是想要什么。该答案中最初提出的方法具有将此类“跨界”周的汇总数据分成两部分的效果:一个与前一年,一个与新年。 在会计等方面通常需要以最多两个部分周为代价的每年一次的干净利落,因此这种方法更好。YEAR() / WEEK()
YEAR() / WEEK()

于 2009-11-14T23:47:57.807 回答
51

想通了……这有点麻烦,但就是这样。

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

而且,如果您的业务规则规定您的周从星期一开始,-1请将-2.


编辑

几年过去了,我终于有时间写这篇文章了。 https://www.plumislandmedia.net/mysql/sql-reporting-time-intervals/

于 2009-11-15T00:51:16.837 回答
41

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

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
于 2012-08-01T12:46:21.853 回答
26

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

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

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

对于按月排序,您可能会考虑使用LAST_DAY()函数 - 将按月的最后一天排序,但这应该等同于按月的第一天排序......不是吗?

于 2009-11-14T23:58:18.650 回答
4

只需在 select 中添加这个:

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

group_by(week);
于 2010-08-31T08:58:56.203 回答
3

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

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

我不得不使用额外的 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;
于 2011-01-18T02:28:07.323 回答
3

上周日:

STR_TO_DATE(CONCAT(YEARWEEK(timestamp,2),'0'),'%X%V%w')

上周一:

STR_TO_DATE(CONCAT(YEARWEEK(timestamp,3),'1'),'%x%v%w')

DATE_FORMAT(date,format)参考

  • %V- 周 (01..53),其中星期日是一周的第一天;WEEK() 模式2 ; 与%X
  • %v- 周 (01..53),其中星期一是一周的第一天;WEEK() 模式3 ; 与%x
  • %w- 星期几(0=星期日..6=星期六)
  • %X- 星期天是一周的第一天的一周年,数字,四位数字;与%V
  • %x- 一周的年份,其中星期一是一周的第一天,数字,四位数字;与%v
于 2021-08-24T02:15:15.333 回答
1

我喜欢 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 周,我们减去同一周的第一天的任何一周月 - week()for2021-02-01是 5,因为它是在一年中的第 5 周:

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

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

于 2021-03-26T22:09:48.690 回答
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'
于 2021-07-10T06:11:32.280 回答