Для этого можно использовать различные функции, такие как DATEPART и DATETIFF . Однако реальная проблема не в том, как выразить условие StartDate или EndDate, приходящееся на данный месяц, а в том, как сделать это таким образом, чтобы сделать запрос эффективным. Другими словами, как выразить это в форме SARGable.
Если вы выполняете поиск в маленькой таблице изменений, размером менее 10 тыс. Страниц, тогда это не имеет большого значения, полное сканирование, вероятно, будет вполне приемлемым. Реальный вопрос заключается в том, значительны ли размер таблицы и полное сканирование неприемлемо.
Если у вас нет индекса ни по одному из столбцов StartDate или EndDate, это не имеет значения, критерии не доступны для поиска, и запрос все равно будет сканировать всю таблицу. Однако, если в StartDate и EndDate имеются индексы, то способ выражения условия имеет все значение. Важной частью для индексов DATETIME является то, что вы должны выражать поиск в точном диапазоне дат. Выражение условия как функции в зависимости от поля DATETIME сделает условие неисследимым, что приведет к полному сканированию таблицы. Таким образом, эти знания правильно отображаются в диапазоне дат:
select ... from table
where StartDate between '20091101' and '20091201'
or EndDate between '20091101' and '20091201';
Это также может быть выражено как:
select ... from table
where StartDate between '20091101' and '20091201'
union all
select ... from table
where EndDate between '20091101' and '20091201'
and StartDate not between '20091101' and '20091201';
Какой запрос работает лучше, зависит от ряда факторов, таких как размер таблицы и статистика фактических данных в таблице.
Однако вы хотите, чтобы ноябрьский месяц начинался с любого года, который этот запрос вам не даст. Решение этой проблемы против каждого инстинкта, который имеет программист: жесткий код соответствующих лет. В большинстве случаев таблицы в любом случае имеют небольшой набор лет, что находится в диапазоне 4-5 лет прошлых данных, и планируйте еще 3-4 года, пока система не будет капитально отремонтирована:
select ... from table
where StartDate between '20051101' and '20051201'
or EndDate between '20051101' and '20051201'
union all
select ... from table
where StartDate between '20061101' and '20061201'
or EndDate between '20061101' and '20061201'
union all
...
select ... from table
where StartDate between '20151101' and '20151201'
or EndDate between '20151101' and '20151201';
В году 12 месяцев, напишите 12 отдельных процедур. Это звучит безумно? Конечно, это так, но это оптимальная вещь с точки зрения компилятора и оптимизатора SQL-запросов. Как можно поддерживать такой код? 12 отдельных процедур, с запросом, который повторяется 10 раз (20 раз, если вы используете UNION между StartDate и EndDate для удаления ИЛИ), 120 повторений кода, это должно быть бессмысленным. На самом деле это не так. Используйте генерацию кода для создания процедур, таких как XML / XSLT, чтобы вы могли легко изменять и поддерживать их. Должен ли клиент знать о 12 процедурах и вызвать соответствующую? Конечно, нет, он вызывает одну процедуру-обертку, которая различает аргумент @Month для вызова правильной.
Я считаю, что любой, кто будет смотреть на систему после фактов, скорее всего, поверит, что этот запрос был написан группой пьяных обезьян. Тем не менее, где-то между анализом параметров, индексом SARGability и SQL DATETIME изумляет, в результате получается, что это состояние дел на сегодняшний день, когда оно относится к поиску календарных интервалов.
Да, и если запрос достигнет критической точки индекса , это все равно отключит весь аргумент ...
Обновление
Кстати, есть и дешевый выход, если вы готовы пожертвовать некоторым пространством хранения: два постоянных вычисляемых столбца для StartMonth AS DATEPART(month, StartDate)
и EndDate AS DATEPART(month, EndDate)
, индекс для каждого и запрос WHERE StartMonth = @Month OR EndMonth = @Month
(или снова UNION между двумя запрашивает один для начала, один для конца, чтобы удалить ИЛИ).