2012-03-19 2 views
2

Я пытаюсь написать запрос выбора, где мой 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

EDIT

Просто, чтобы сделать его более ясным, я не хочу доверять моим @FromMonth и @ToMonth вход знать последний день в течение месяца. Вышеприведенное является лишь примером для иллюстрации моей проблемы.

+0

Действительно, что вам нужно ??? –

+0

Вы пробовали это? -> set @ToMonth = '20120331' – Zohaib

+0

Это потому, что в вашем дате есть дата, и вы не указали, что хотите, чтобы МЕЖДУ не беспокоился о год и месяц. попытайтесь использовать функции MONTH() и YEAR(), или установите свой ToMonth до последнего дня месяца –

ответ

4

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 включает в себя времени.

+0

+1 для указания OP на использование ' = X и MatBailie

+0

Как и ваше простое решение, хотя я нахожу его немного мошенническим, что вы изменили вход @ToMonth, посмотрим и посмотрим если я смогу сделать остальную часть моего кода работать вместе с ним. – gulbaek

+2

@gulbaek - Это не обман, это исправление. Ваш ввод - это значение DATETIME, * * непрерывное *. '20120301' не означает« весь марш », это означает« 00:00 1 марта ». 'BETWEEN' для дискретных значений, таких как целые числа. Используйте '> =' и '<' для непрерывных значений. Если поле было FLOAT, вы не ожидали бы 'WHERE my_float BETWEEN 1 AND 2' включить' 2.9'. Для этого вы должны сказать 'WHERE my_float> = 1 AND my_float <3'. Точно так же, в вашем случае, если бы вы хотели ровно один месяц, ваши параметры были бы «20120101», но между этими значениями нет времени. Использование '<' делает это более разумным. – MatBailie

1

Измените ваш ИНЕКЕ что-то вроде:

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

Это уничтожит вероятность использования оптимизатором индексов эффективно. Чтобы разрешить этот запрос, требуется полная проверка, а не гораздо более быстрый поиск. – MatBailie

2

Первый DateAdd/DateDiff пара возвращает первый день месяца, второй возвращает первый день следующего месяца:

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

EDIT: изменил мой ответ согласно советам демонов.

+0

А что, если у OrderDate есть временная часть? Все, что после '00: 00' утром в последний день месяца, игнорируется. См. Ответ @ Damien_The_Unbeliever; используйте '> = и <' для непрерывных значений. 'BETWEEN' следует использовать только для дискретных значений. – MatBailie

+0

Спасибо @Dems. Я отредактировал свой ответ соответственно. –

+0

+1 как это сейчас работает, и я не хочу, чтобы он был зажат между неправильными арабами :) – MatBailie

0
WHERE MONTH(*col name*) between'01' and '05' 

это даст данные/б января по май и имя цв должно быть ДАТА COLUMN.

Смежные вопросы