【问题标题】:MySQL: IN clause for dates BETWEEN a start and end date?MySQL:开始日期和结束日期之间的日期的 IN 子句?
【发布时间】:2011-11-04 19:56:40
【问题描述】:

我有YYYY-MM 格式的日期列表,并且我有一个包含starts_atends_at 列的记录表。

我想查找传入列表中任何给定日期在starts_atends_at 范围内的所有记录。

所以,鉴于2011-01, 2011-05, 2011-10,我想要:

| id | starts_at           | ends_at             | title                             |
| 3  | 2010-12-05 00:00:00 | 2011-02-02 00:00:00 | something cool                    |
| 4  | 2011-03-14 00:00:00 | 2011-05-01 00:00:00 | something else really cool        |
| 5  | 2011-10-31 00:00:00 | 2012-12-23 00:00:00 | argh! end of the world! not cool! |

...虽然这些记录将被省略:

| id | starts_at           | ends_at             | title                             |
| 6  | 2010-10-05 00:00:00 | 2010-12-02 00:00:00 | something uncool                  |
| 7  | 2011-03-14 00:00:00 | 2011-04-31 00:00:00 | something else really uncool      |
| 8  | 2011-12-23 00:00:00 | 2013-01-01 00:00:00 | yay! we're still alive! cool!     |

如何在 SQL 中编写 WHERE 条件?


澄清:我正在寻找纯 SQL 的解决方案(我正在使用存储过程,因此通过 PHP 等其他语言进行动态注入实际上是不可能的,至于我知道),日期列表作为string(HTML 表单输入)传递给查询。如果我可以在 SQL 中以编程方式执行此操作,我很乐意将其分解为连续的 BETWEEN 语句,但我不知道如何执行此操作。

基本上,我需要一种在纯 SQL 中表达以下逻辑的方法:

$months = explode(',', '2011-01,2011-05,2011-10');
$q = "SELECT records.* FROM records WHERE";
foreach($months as $month) {
  $q .= " '$month' BETWEEN records.starts_at AND records.ends_at OR";
}
$q = substr($q, 0, -3) . ';';

【问题讨论】:

    标签: mysql sql


    【解决方案1】:
    SELECT id, starts_at, ends_at, title
    FROM yourtable
    WHERE '2011-01-01' BETWEEN starts_at AND ends_at
    OR    '2011-05-01' BETWEEN starts_at AND ends_at
    OR    '2011-10-01' BETWEEN starts_at AND ends_at
    

    【讨论】:

    • 不完全是我所追求的...日期列表是传递给查询的字符串,而不是作为单个变量...像这样:WHERE record.an_imaginary_date_field IN (2011-01, 2011-05, 2011-10)...除非有在 SQL 中解析该字符串以获取单独值的方式?
    • @neezer:最好在客户端将其解析为单独的值。
    • @MarkByers 没有 SQL-only 方法来完成这个吗?我在这里使用一个相当复杂的存储过程。没有办法将月份数组传递给存储过程来代替内爆字符串,然后遍历该数组以执行上面列出的BETWEEN 语句?
    • @MarkByers,你试过这个吗?对我来说,这只适用于 starts_atends_at 是字符串。如果它们是 DATETIME 或 TIMESTAMP 列,MySQL 会将字符串 YYYY-MM 值 (ER_TRUNCATED_WRONG_VALUE) 清空,因此 BETWEEN 将始终为 false。
    • @pilcrow:他说他的问题是字符串。
    【解决方案2】:

    您可以将月份说明符转换为月初和月底(someom 下面)并自己动手:

    SET sql_mode='ansi';
    
    SELECT neezer.*
      FROM neezer
      JOIN (SELECT m || '-01' AS som,
                   DATE_SUB(DATE_ADD(m || '-01', INTERVAL 1 MONTH), INTERVAL 1 SECOND) AS eom
              FROM (SELECT '2011-01' AS m
                     UNION ALL
                    SELECT '2011-05'
                     UNION ALL
                    SELECT '2011-10') d) month_intervals
           ON som <= ends_at AND eom >= starts_at;
    

    因此,我们将每个'2011-01' 转换为成对的 DATE 和 DATETIME,然后计算重叠。 (我们将eom 转换为'YYYY-MM-DD 23:59:59' 的原因是'2011-01' 匹配starts_at'2011-01-01 01:00:00' 的间隔(否则@987654328 @ 将在第一天被强制为 00:00:00,并且与我们的 starts_at 不匹配。

    【讨论】:

    • 嗯,你有什么理由不在这里使用BETWEEN 吗?另外,有没有在纯 SQL 中以编程方式执行此操作?请参阅我上面的编辑以了解我的意思...
    • @neezer,我假设 starts_atends_at 是时间类型,而不是字符串。请参阅我对 MarkByer 回答的评论。至于您的“纯 SQL”问题,不。但是,您自己设计的存储过程可能能够拆分字符串并输出正确的查询或使用您关心的日期范围填充临时表。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-05
    • 2017-01-05
    • 2016-05-15
    相关资源
    最近更新 更多