日期之间的日期,忽略年份

Posted

技术标签:

【中文标题】日期之间的日期,忽略年份【英文标题】:Date between dates, ignore year 【发布时间】:2014-09-01 00:23:58 【问题描述】:

如果日期在独立于年份的日期范围内,最好(最快)的比较方法是什么?

表格“日期”:

    some_column| since        | upto        |  
    -----------|--------------|-------------|
   'foo'       | '2011-05-01' | '2013-06-01'|

现在我希望这个查询返回 'foo'

SELECT foo FROM dates WHERE '2014-05-05' BETWEEN `since` AND `upto`

如果需要,我可以更改“日期”表中存储日期的类型/格式,但我无法更改输入查询的日期格式,因为该值通常来自另一个表(它是使用连接的更复杂查询的一部分)。

【问题讨论】:

目前它们以日期类型存储。我只是说如果需要,我可以改变它。 日期不是“格式”。它是一种类型。 好的,你知道了。我就是这个意思。 你还没有解释“独立于年份”是什么意思 这可能会有所帮助***.com/questions/23446462/… 【参考方案1】:

使用DayOfYear函数:

 SELECT foo FROM dates WHERE DayOfYear('2014-05-05') 
    BETWEEN DayOfYear(`since`) AND DayOfYear(`upto`)

【讨论】:

好主意。我也考虑过。但闰年会度过难关。 3 月 1 日是非闰年的第 60 天,但闰年的第 61 天。 如果 mysql 还没有对此进行调整,另一种选择是滚动您自己的 Julianizer 类型函数(MONTH(dt)*100 + DAY(dt) 应该这样做)。 我不清楚如何将 julianizer 集成到您发布的查询中,您能澄清一下吗? 直接使用它来代替 DayOfYear:SELECT foo FROM dates WHERE MONTH('2014-05-05')*100 + DAY('2014-05-05') BETWEEN (MONTH(since)*100 + DAY(since)) AND (MONTH(upto)*100 + DAY(upto)) 确实是个好主意,但您还需要针对sinceupto 不是同一年的情况进行调整,即。例如,since 是 12 月,upto 是 1 月。您的测试将选择 1 月到 12 月之间的日期,而不是 12 月到 1 月之间的日期。【参考方案2】:
SELECT foo FROM dates WHERE DATE_FORMAT('2014-01-15', "%m-%d") 
    BETWEEN DATE_FORMAT(`since`,"%m-%d") AND DATE_FORMAT(`upto`,"%m-%d")

这是SQL FIDDLE 演示

【讨论】:

挖掘它,很好的解决方案。 ?【参考方案3】:

既然您表示可以在数据中存储任意年份,那么您可以继续使用DATE 类型。然后就是如何查询了。

使用固定的任意年份存储字段。您应该使用闰年来适应 2 月 29 日值的可能性。 2000 年运行良好。 (0004 不起作用,因为它对于 MySQL 的 Date 类型来说太小了。)

将您查询的任何值的年份替换为同一年份。

考虑跨越一年结束并进入下一年的范围。要完全回答这个问题,您需要如下查询:

SET @dt = cast(CONCAT('2000',RIGHT(thesourcedatevalue,6)) as DATE);

SELECT some_column FROM dates
WHERE (since <= upto AND since <= @dt AND upto >= @dt) OR
      (since > upto AND (since <= @dt OR upto >= @dt))

Here is a SQL Fiddle that demonstrates

为了提高性能,您应该确保存在包含sinceupto 字段的索引。

【讨论】:

a) 0004 对于 mysql 的日期类型来说并不算小。 b)它不起作用,我什至不知道它是如何起作用的。最后一对括号中的条件没有意义。另外,我不能用固定年份存储“@dt”。可以是 2000 年,也可以是 2014 年,任何年份。我多次说过我可以更改表格中的格式/类型/年份,但不能更改他们比较的日期。我希望您的建议将包括将“@dt”年份替换为 2000 年的方法 每个these docs DATE 类型支持的范围是1000-01-019999-12-31 WHERE 语句的第二行(包括括号中的最后一个条件)用于涵盖我描述的情况,其中范围从 12 月到 1 月,跨越了年份边界。如果你没有这种情况,你可以删除整行。 我真的不确定你对其余部分的意思。您不是在 存储 @dt - 这是您查询的参数。您应该能够在查询之前轻松操作它。 好的,让我们测试你的第二个条件:since=march,upto=january,"@dt"=february。所以二月是在一月和三月之间,对吧?行。所以三月 > 一月 AND(三月 = 二月)。它失败。看?如果您认为我可以手动更改查询中比较列的日期的年份,那么我不明白为什么要使用这个复杂的查询而不继续使用。尽管如此,我从一开始就解释说这个值通常是 JOIN 的结果,我不能改变它。我可以在日期字段中输入 0004 作为年份。【参考方案4】:

在简单的 google-look 和 stackoverlook 之后,我遇到了两个问题:

某年多出 1 天(2 月 29 日) 询问的范围(sinceupto)可以属于不同的年份,使用 DayOfYear() 是个问题。这是我想出的 sql 查询。

假设我们有一个日期“2014-05-05”要检查:

SELECT foo FROM `dates` WHERE
        (
    /*     --------    since and upto are from same year    --------    */
            YEAR(`since`) = YEAR(`date_fin`)
            AND (
                (
                    MONTH(`since`) < "05"
                    OR
                    (
                        MONTH(`since`) = "05"
                        AND
                        DAY(`since`) <= "05"
                    )
                ) AND (
                    MONTH(`date_fin`) < "05"
                    OR
                    (
                        MONTH(`date_fin`) = "05"
                        AND
                        DAY(`date_fin`) >= "05"
                    )
                )
            )
        )OR(
    /*     --------    since and upto are from different year    --------    */
            YEAR(`since`) <> YEAR(`date_fin`) AND (
                (
                    MONTH(`since`) < "05"
                    OR
                    (
                        MONTH(`since`) = "05"
                        AND
                        DAY(`since`) <= "05"
                    )
                ) OR (
                    MONTH(`date_fin`) > "05"
                    OR
                    (
                        MONTH(`date_fin`) = "05"
                        AND
                        DAY(`date_fin`) >= "05"
                    )
                )
            )
        )

【讨论】:

我不明白这些是什么问题。 dayOfYear 不在乎,因为和 upto 是不同的年份,是的,有些年份有不同的天数,dayOfYear 应该已经考虑到这一点【参考方案5】:

我通过以下方式解决了类似的问题:

SELECT foo FROM dates

WHERE   '0000-05-05'
BETWEEN SUBDATE(since, INTERVAL YEAR(since) YEAR)
AND     SUBDATE(upto, INTERVAL YEAR(since) YEAR)

OR      ADDDATE('0000-05-05', INTERVAL 1 YEAR)
BETWEEN SUBDATE(since, INTERVAL YEAR(since) YEAR)
AND     SUBDATE(upto, INTERVAL YEAR(since) YEAR)

首先,我们将所有日期重置为零,接下来我们在两个范围之间寻找特定日期(也重置为零)。在后面的示例中,我们已经从外部源传递了“重置”日期,但这也可以在 mysql 中完成:

WHERE   SUBDATE('2014-05-05', INTERVAL YEAR('2014-05-05') YEAR)

【讨论】:

以上是关于日期之间的日期,忽略年份的主要内容,如果未能解决你的问题,请参考以下文章

在没有年份的 2 个日期之间搜索

SQL查询选择年份在两个日期之间的行

Wp查询日期之间的帖子,但任何年份

检查日期是不是在 sql 中的日期范围之间(不检查年份)

计算两个日期之间的年份 laravel

sql server 中两个日期之间的年份以及每个日期在 sql server 中的开始和结束日期