2010-01-04 3 views
8

Как сравнить только временную часть типа данных DateTime в SQL Server 2005? Например, я хочу получить все записи, в которых MyDateField выполняется через определенное время. Следующий пример - очень длинный и, вероятно, не быстрый способ сделать это. Я хочу, чтобы все даты, когда MyDateField больше 12: 30: 50,400Сравнение временной части типа данных DateTime в SQL Server 2005

SELECT * 
FROM Table1 
WHERE  ((DATEPART(hour, MyDateField) = 12) AND (DATEPART(minute, MyDateField) = 30) AND (DATEPART(second, MyDateField) = 50) AND (DATEPART(millisecond, MyDateField) > 400)) 
     OR ((DATEPART(hour, MyDateField) = 12) AND (DATEPART(minute, MyDateField) = 30) AND (DATEPART(second, MyDateField) > 50)) 
     OR ((DATEPART(hour, MyDateField) = 12) AND (DATEPART(minute, MyDateField) > 30)) 
     OR ((DATEPART(hour, MyDateField) > 12)) 
+0

Обратите внимание, что если вам действительно нужно обработать дату и время по отдельности, вы эффективно нарушаете правила нормализации. Значение DateTime - это конкретный момент времени в дате. Дата и время - это многозначное поле, которое должно быть разбито. Причина, по которой ваш код работает медленно, заключается в том, что вы его нормализовали неправильно. –

+0

@ Lasse - как далеко вы это возьмете? Конечно, вы не храните: день, месяц, год, час, минуту, день недели, выходные, квартал, неделю в отдельных полях вместо того, чтобы просто хранить дату. – JeffO

+0

@ Lasse - Конечно, я мог бы отделить поле DateTime в полях Дата и Время. Но тогда у меня была бы такая же проблема, чтобы сравнивать дату и время вместе. –

ответ

10
SELECT * 
FROM Table1 
WHERE DATEADD(day, -DATEDIFF(day, 0, MyDateField), MyDateField) > '12:30:50.400' 
+0

Я думаю, что это лучшее решение. Это понятно и легко понять. Также это самое быстрое решение, касающееся только запроса, а не структуры БД. –

5

Как насчет этого?

SELECT (fields) 
FROM dbo.YourTable 
WHERE DATEPART(HOUR, MyDate) >= 12 
    AND DATEPART(MINUTE, MyDate) >= 23 
    AND DATEPART(SECOND, MyDate) >= 45 

Часы указаны в 24-часовом формате, например. 12 означает 12-часовой полдень, 15 означает 3 часа.

DATEPART также имеет «детали» в течение нескольких минут, секунд и так далее. Разумеется, вы можете использовать как многие из этих элементов даты в своем предложении WHERE, как вам нравится.

+0

Если полдень - это отсечка, то логика должна, вероятно, быть либо «час» = 12, либо, может быть, «час» 12 или (час = 12 и миллисекунда> 0) ». – LukeH

+0

@ Luke: хорошая точка, да - я хотел использовать> = .... –

+0

Но я также хочу рассмотреть другие части части времени, а не только час. –

-1

новообращенный (VARCHAR (10), MyDate, 108)

Это дает временную строку в формате HH: MM: SS.

Вы можете сделать любое сравнение вы хотите с ним

+0

Временная часть также включает миллисекунды ... есть ли формат, который также возвращает полную часть времени? То, что я ищу, является способом исключения части Date, оставляющей только время. –

1

То, что я хотел сделать, это извлечь временную часть типа DateTime данных, и сравнить его. Я нашел способ извлечь часть даты здесь в StackOverflow. Если у меня есть часть даты в одиночку, она просто вычесть дату из источника DateTime:

datePortion = DATEADD (день, DATEDIFF (день 0, sourceDate), 0)
timePortion = DATEDIFF (миллисекунды, datePortion, sourceDate)

таким макро, чтобы извлечь часть времени в SQL Server 2005 является:

F (X) = DATEDIFF (миллисекунду, DATEADD (день, DATEDIFF (день 0, sourceDate), 0), sourceDate)

Теперь запрос для сравнения времени части поля DateTime, с 12: 30: 50,400 является:

SELECT * 
FROM Table1 
WHERE 
     DATEDIFF(millisecond, DATEADD(day, DATEDIFF(day, 0, DateTimeField), 0), DateTimeField) 
     > 
     DATEDIFF(millisecond, DATEADD(day, DATEDIFF(day, 0, '1900-01-01T12:30:50.400'), 0), '1900-01-01T12:30:50.400') 

Я проверил этот запрос в отношении других видов запросов, в том числе с помощью оператора вычитания ('-') и CONVERT. Сравнение плана выполнения показывает, что это самый быстрый способ сделать это. Я также тестировал реальные времена выполнения запроса ... нет заметного быстрого метода.

+0

Для того чтобы убрать запрос, а не улучшать производительность, это довольно хорошее решение, если вы вбрасываете его в UDF. Таким образом вы можете записать его как 'WHERE dbo.GetTime (MyDateField)> = @ SomeTime'. – Aaronaught

+0

В начале мне было интересно, могу ли я увеличить производительность, только меняя запрос. Это возможно, но не так много, менее 2%. Мне не удалось найти функцию GetTime. –

1

Другие выложили альтернативные методы формирования запроса, но я хочу, чтобы реагировать на то, что вы говорите в первом абзаце:

Следующий пример очень долго и , вероятно, не быстрый способ сделать это.

С точки зрения производительности, это на самом деле не имеет значения, если у вас есть один DATEPART или 10 DATEPARTS в там; тот факт, что у вас есть один DATEPART, - это то, что может повредить производительность.

Если вам нужно сравнить по времени, но не по дате, то комментарий Лассе прямо на деньги - вам нужно нормализовать в отдельные столбцы даты/времени. Фактически, SQL 2008 вводит date и time и рекомендует использовать их вместо datetime. У вас этого нет в SQL 2005, но вы можете обойти его, скажем, в поле тиков для времени суток, и контрольное ограничение, которое заставляет все столбцы даты столбца даты равняться нулю.

Если вам необходимо выполнить фильтрацию в полную дату + время, легко создать вычисленный столбец, и если производительность для них является проблемой, вы можете сохранить этот столбец и создать на нем индекс.

+0

Вы полностью верны! =) Я задал вопрос, потому что я хотел знать, как его решить, так оно и есть, не меняя БД. На самом деле все решения QUERY-ONLY - это тот же порядок скорости, все равно все равно будет медленным ... Я тестировал его прямо сейчас ... но использование DATEADD и DATEDIFF является лучшим среди худших. –