Вопрос по извлечению записей на основе диапазона дат - PullRequest
1 голос
/ 10 октября 2010
SELECT COUNT(td.timeSheetID) FROM TimeSheet t 
INNER JOIN TimeSheetDetail td ON t.timeSheetID = td.timeSheetID 
WHERE (CONVERT(DateTime, t.setDate, 23) BETWEEN '2012-08-10' AND '2012-08-12') 
AND t.employeeID = 300

Приведенный выше код возвращает значение, которое я ищу.Однако, когда я делаю следующее, я ничего не получаю:

    SELECT COUNT(td.timeSheetID) FROM TimeSheet t INNER JOIN TimeSheetDetail td ON t.timeSheetID = td.timeSheetID 
    WHERE (CONVERT(DateTime, t.setDate, 23) = '2012-08-11') 
    AND t.employeeID = 300

значение setDate в таблице выглядит так:

2012-08-11 18: 00: 19.000

Мои вопросы:

  1. Почему код в первом сценарии работает нормально, а во втором не работает?

  2. Почему код в первом сценарии не возвращает значение, когда я задаю фактический диапазон как «2012-08-11» И «2012-08-11» ... Как я могу решить проблему, я не знаюt время, которое нужно учитывать во время диапазона / фильтрации.Я только подумываю о дате.

Ответы [ 2 ]

2 голосов
/ 10 октября 2010
  • Не пишите запросы, которые используют функции для столбцов для сравнения с константами.Это делает их недоступными для SARG, и невозможно использовать конечный индекс для столбца setDate.
  • Не используйте литералы, где можно использовать параметр
  • Если необходимо использовать литералыдля даты и времени используйте формат неразделенной строки , поскольку он не зависит от языка и всегда интерпретируется как ymd.

В заключение:

SELECT COUNT(td.timeSheetID) FROM TimeSheet t 
INNER JOIN TimeSheetDetail td ON t.timeSheetID = td.timeSheetID 
WHERE t.setDate BETWEEN @dateFrom AND @dateTo 
AND t.employeeID = @employeeId;

или (хуже):

SELECT COUNT(td.timeSheetID) FROM TimeSheet t 
INNER JOIN TimeSheetDetail td ON t.timeSheetID = td.timeSheetID 
WHERE t.setDate BETWEEN '20120810' AND '20120812'
AND t.employeeID = 300;

Что касается вашего вопроса, лучший способ отсканировать «день» в диапазоне даты и времени - это выразить день как диапазон:

SELECT COUNT(td.timeSheetID) FROM TimeSheet t 
INNER JOIN TimeSheetDetail td ON t.timeSheetID = td.timeSheetID 
WHERE t.setDate >= '20120811' AND t.setDate < '20120812'
AND t.employeeID = 300;

Это будет охватывать все часы 20120811. Разумеется, лучше ли использовать параметры вместо литералов.

И, наконец, реальный вопрос будет, если у вас есть индекс покрытия для этого запроса.Временные ряды, как и таблица «расписания», почти всегда связаны по диапазону дат, поэтому кластерный индекс по (employeeID, setDate), вероятно, является хорошим выбором.Второй лучший выбор - некластеризованный индекс для того же самого.

1 голос
/ 10 октября 2010

Когда вы используете CONVERT и изменяете значение на DATETIME, время не удаляется.Таким образом, сравнение со значениями даты не будет совпадать.Попробуйте следующее, чтобы увидеть, что происходит

SELECT CONVERT(DateTime, t.setDate, 23)
FROM TimeSheet t

Чтобы сбросить время с даты и времени, измените выражение CONVERT, чтобы результат приводился к типу данных varchar

CONVERT(varchar, t.setDate, 23)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...