【问题标题】:Select between two months选择两个月
【发布时间】:2012-03-19 09:36:52
【问题描述】:

我正在尝试编写一个选择查询,其中我的 OrderDate 介于两个月之间。 这是我目前的代码。

declare @FromMonth datetime
declare @ToMonth datetime
set @FromMonth = '20111201'
set @ToMonth = '20120301'

select *
from Order o
where o.OrderDate between @FromMonth and @ToMonth

这几乎可以工作,除了它还查看月份中的某天,这意味着在此示例中它不会选择我的 @ToMonth 中的所有日期

我使用的是 Sql Server 2012

编辑

为了更清楚,我不想相信我的@FromMonth 和@ToMonth 输入来知道该月的最后一天。以上只是一个示例来说明我的问题。

【问题讨论】:

  • 你试过了吗? -> 设置@ToMonth = '20120331'
  • 这是因为您的日期时间有一个日期,并且您没有指定您只希望 BETWEEN 关心年和月。尝试使用 MONTH() 和 YEAR() 函数,或设置您的ToMonth 到该月的最后一天
  • @OriesokVlassky - 不,真的,请不要这样做。它将破坏使用 INDEX SEEK 的能力,并会产生完整的扫描。如果您想要任何体面的性能,请不要将搜索字段包装在函数中。
  • @gulbaek - 在您的编辑中,您说您不想相信您的输入。请参阅@Nikola 使用 DATEADD/DATEDIFF 将值舍入到月初的答案,以便您可以在>=< 中使用它们。您可能会决定对输入进行稍微不同的清理,但是如果您能理解该答案,那么您应该可以按照自己的喜好对输入进行清理:)

标签: sql datetime sql-server-2012


【解决方案1】:

between 很少像您希望的那样工作,我通常发现将范围写为包含/排除对并应用适当的比较会更好:

declare @FromMonth datetime
declare @ToMonth datetime
set @FromMonth = '20111201'
set @ToMonth = '20120401'

select *
from Order o
where o.OrderDate >= @FromMonth and o.OrderDate < @ToMonth

如果OrderDate 包含时间组件,这也将避免麻烦。

【讨论】:

  • +1 用于将 OP 指向使用 &lt; end_point。 DATETIMEs 实际上是连续值,人们应该始终使用&gt;= X and &lt; Y
  • 就像你的简单解决方案一样,虽然我觉得它有点作弊,但你更改了@ToMonth 输入,我会看看我是否可以让我的其余代码一起工作它。
  • @gulbaek - 这不是作弊,而是修复。您的输入是一个 DATETIME,一个 连续 值。 20120301 并不意味着“所有的三月”,它的意思是“3 月 1 日 00:00”。 BETWEEN 用于离散值,如整数。对于连续值,请使用 &gt;=&lt;。如果该字段是 FLOAT,您不会期望 WHERE my_float BETWEEN 1 AND 2 包含 2.9。为此,您应该说WHERE my_float &gt;= 1 AND my_float &lt; 3。同样,在您的情况下,如果您想要一个月,您的参数都将是20120101,但这些值之间没有时间。使用&lt; 更有意义。
  • @gulbaek - 尽管@Dems 的评论很好,但如果您仍然希望@ToMonth 等于'20120301',您可以随时在查询中将@ToMonth 替换为DATEADD(month,1,@ToMonth)
【解决方案2】:

第一个 dateadd/datediff 对返回一个月的第一天,第二个返回下个月的第一天:

where o.OrderDate >= dateadd(m, datediff (m, 0, @FromMonth), 0) 
  and o.OrderDate < dateadd(m, datediff (m, 0, @ToMonth) + 1, 0)

编辑:根据 dems 的建议更改了我的回复。

【讨论】:

  • 如果 OrderDate 有时间部分怎么办?当月最后一天早上00:00 之后的任何内容都会被忽略。请参阅@Damien_The_Unbeliever 的回答;使用 &gt;= and &lt; 获取连续值。 BETWEEN 只能用于离散值。
  • +1 因为这现在有效,我不希望它被夹在错误的 asnwers 之间:)
【解决方案3】:

将您的 WHERE 子句更改为:

WHERE (MONTH(o.OrderDate) BETWEEN MONTH(@FromMonth) AND MONTH(@ToMonth))
AND (YEAR(o.OrderDate) BETWEEN YEAR(@FromMonth) AND YEAR(@ToMonth))

【讨论】:

  • 这将破坏优化器有效使用索引的机会。要解决此查询需要进行全面扫描,而不是更快的搜索。
【解决方案4】:
WHERE MONTH(*col name*) between'01' and '05'

这将给出一月到五月的数据,列名应该是日期列。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-04-07
    • 2015-12-25
    • 1970-01-01
    • 2021-09-14
    • 2018-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多