日期之间的日期,忽略年份
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))
确实是个好主意,但您还需要针对since
和upto
不是同一年的情况进行调整,即。例如,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
为了提高性能,您应该确保存在包含since
和upto
字段的索引。
【讨论】:
a) 0004 对于 mysql 的日期类型来说并不算小。 b)它不起作用,我什至不知道它是如何起作用的。最后一对括号中的条件没有意义。另外,我不能用固定年份存储“@dt”。可以是 2000 年,也可以是 2014 年,任何年份。我多次说过我可以更改表格中的格式/类型/年份,但不能更改他们比较的日期。我希望您的建议将包括将“@dt”年份替换为 2000 年的方法 每个these docsDATE
类型支持的范围是1000-01-01
到9999-12-31
。
WHERE 语句的第二行(包括括号中的最后一个条件)用于涵盖我描述的情况,其中范围从 12 月到 1 月,跨越了年份边界。如果你没有这种情况,你可以删除整行。
我真的不确定你对其余部分的意思。您不是在 存储 @dt
- 这是您查询的参数。您应该能够在查询之前轻松操作它。
好的,让我们测试你的第二个条件:since=march,upto=january,"@dt"=february。所以二月是在一月和三月之间,对吧?行。所以三月 > 一月 AND(三月 = 二月)。它失败。看?如果您认为我可以手动更改查询中比较列的日期的年份,那么我不明白为什么要使用这个复杂的查询而不继续使用。尽管如此,我从一开始就解释说这个值通常是 JOIN 的结果,我不能改变它。我可以在日期字段中输入 0004 作为年份。【参考方案4】:
在简单的 google-look 和 stackoverlook 之后,我遇到了两个问题:
某年多出 1 天(2 月 29 日) 询问的范围(since
和upto
)可以属于不同的年份,使用 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)
【讨论】:
以上是关于日期之间的日期,忽略年份的主要内容,如果未能解决你的问题,请参考以下文章