【问题标题】:Select the year that September is in from a date range从日期范围中选择 9 月所在的年份
【发布时间】:2014-09-24 21:45:31
【问题描述】:

我有一张开始日期和结束日期的表格 - 主要是一整年,但从任何月份开始。

我想获得一份关于每年当前月份活跃的行数的报告。就像计数 - 当前、去年计数、2 年前计数等

我在 PHP 中构建我的查询,因此我可以轻松地在子查询的日期或总和中使用 sum(case when then end) 和硬代码,但我认为可能有更好的方法。有什么想法吗?

【问题讨论】:

  • group by year(datefield), month(datefield) where month(datefield)=$month_you_want?
  • 我有两个日期 - 我检查的日期不太可能是开始或结束。本月是 9 月份连续活跃的年份。例如:2010 年 11 月 1 日 - 2011 年 10 月 31 日将返回 2011 年 例如:2010 年 8 月 1 日 - 2011 年 7 月 31 日将返回 2010 年
  • 我想我会用这个CASE WHEN MONTH(enddate) < MONTH(NOW()) THEN YEAR(enddate)-1 ELSE YEAR(enddate) END AS yeargroup 运行当日期跨度很短时可能会遇到问题,所以我也需要考虑到这一点。
  • 并进一步简化为YEAR(enddate) - IF( MONTH(enddate) < MONTH(NOW()), 1, 0),但仍然没有检查开始日期...

标签: mysql


【解决方案1】:

您可以使用表达式而不是“日期中的硬代码”

要返回当前月份的第一个日期,您可以使用返回当前日期的年份和月份的表达式,并用固定值替换月份的第一个日期,如下所示:

DATE_FORMAT(NOW(),'%Y-%m-01')

提前一年获得

DATE_FORMAT(NOW(),'%Y-%m-01') - INTERVAL 1 YEAR

对于范围比较,检查是否存在“重叠”(表中每一行的start_dateend_date 之间的时间段)以及给定月份的第一天和最后一天,我会做一些事情像这样:

     end_date >= DATE_FORMAT(NOW(),'%Y-%m-01')
AND start_date < DATE_FORMAT(NOW(),'%Y-%m-01') + INTERVAL 1 MONTH 

此模式(大于或等于月初且小于下个月的第一天)适用于日期以及包含时间组件的日期时间。 (此检查假定 end_date 的 NULL 值未用于表示“无结束日期”......需要调整检查以适应这种情况。)

如果我有规范(按照我的解释),我可能会这样做:

 SELECT SUM( t.start_date   < DATE_FORMAT(NOW(),'%Y-%m-01') + INTERVAL   1 MONTH
         AND t.end_date    >= DATE_FORMAT(NOW(),'%Y-%m-01') + INTERVAL   0 MONTH
        ) AS `count_current_year`

      , SUM( t.start_date   < DATE_FORMAT(NOW(),'%Y-%m-01') + INTERVAL -11 MONTH
         AND t.end_date    >= DATE_FORMAT(NOW(),'%Y-%m-01') + INTERVAL -12 MONTH
        ) AS `count_previous_year`

      , SUM( t.start_date   < DATE_FORMAT(NOW(),'%Y-%m-01') + INTERVAL -23 MONTH
         AND t.end_date    >= DATE_FORMAT(NOW(),'%Y-%m-01') + INTERVAL -24 MONTH
        ) AS `count_two_years_ago`

  FROM mytable t

我不知道这会更好。 (它可能比你所拥有的要丑得多,但我不认为里面有什么不合时宜的东西。)

我看不到有效利用 start_dateend_date 上的索引的方法(假设一行代表“日期范围”),除非可以完全从索引(即覆盖索引存在。)

【讨论】:

  • @SarahKing:“诀窍”在于 MySQL 将布尔表达式评估为 1(代表真)、0(代表假)或 NULL(代表 NULL)。这只是一种简写方式,不需要 IF() 函数或更繁琐(但标准)的 CASE 表达式。
【解决方案2】:

不管怎样,您可以检索该字符串出现任何DATEDATETIMETIMESTAMP 项目的月份的第一天。

 DATE(DATE_FORMAT(when, '%Y-%m-01'))

这个小函数在GROUP BY 表达式等中非常有用。

【讨论】:

  • 我经常使用那个小宝石。谢谢你的回答奥利。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-09-23
  • 2018-12-24
  • 1970-01-01
  • 1970-01-01
  • 2016-10-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多