Как я могу сравнить время в SQL Server?
Я пытаюсь сравнить время в поля datetime В SQL-запросе, но я не знаю, что это правильно. Я не хочу сравнивать даты, только время.
Я делаю так:
SELECT timeEvent
FROM tbEvents
WHERE convert(datetime, startHour, 8) >= convert(datetime, @startHour, 8)
это правильно?
Я спрашиваю об этом, потому что мне нужно знать, если '08:00:00' меньше или больше, чем '07:30:00', и я не хочу сравнивать дату, только часть времени.
спасибо!
16 ответов:
ваше сравнение будет работать, но это будет медленно, потому что времени преобразуются в строку для каждой строки. Чтобы эффективно сравнить две части времени, попробуйте:
declare @first datetime set @first = '2009-04-30 19:47:16.123' declare @second datetime set @second = '2009-04-10 19:47:16.123' select (cast(@first as float) - floor(cast(@first as float))) - (cast(@second as float) - floor(cast(@second as float))) as Difference
длинное объяснение: дата в SQL server хранится как число с плавающей запятой. Цифры перед десятичной точкой представляют дату. Цифры после десятичной точки представляют время.
Итак, вот пример даты:
declare @mydate datetime set @mydate = '2009-04-30 19:47:16.123'
давайте преобразуем его в a поплавок:
declare @myfloat float set @myfloat = cast(@mydate as float) select @myfloat -- Shows 39931,8244921682
Теперь возьмите часть после цифры, т. е. время:
set @myfloat = @myfloat - floor(@myfloat) select @myfloat -- Shows 0,824492168212601
преобразовать его обратно в datetime:
declare @mytime datetime set @mytime = convert(datetime,@myfloat) select @mytime -- Shows 1900-01-01 19:47:16.123
1900-01-01-это просто "нулевая" дата; вы можете отобразить часть времени с помощью convert, указав, например, формат 108, который является только временем:
select convert(varchar(32),@mytime,108) -- Shows 19:47:16
преобразования между datetime и float довольно быстро, потому что они в основном хранятся таким же образом.
convert(varchar(5), thedate, 108) between @leftTime and @rightTime
объяснение:
если у вас
varchar(5)
вы получаетеHH:mm
если у вас
varchar(8)
вы получаетеHH:mm ss
108 получает только время от даты SQL
@leftTime
и@rightTime
две переменные для сравнения
Если вы используете SQL Server 2008, Вы можете сделать это:
WHERE CONVERT(time(0), startHour) >= CONVERT(time(0), @startTime)
вот полный тест:
DECLARE @tbEvents TABLE ( timeEvent int IDENTITY, startHour datetime ) INSERT INTO @tbEvents (startHour) SELECT DATEADD(hh, 0, GETDATE()) INSERT INTO @tbEvents (startHour) SELECT DATEADD(hh, 1, GETDATE()) INSERT INTO @tbEvents (startHour) SELECT DATEADD(hh, 2, GETDATE()) INSERT INTO @tbEvents (startHour) SELECT DATEADD(hh, 3, GETDATE()) INSERT INTO @tbEvents (startHour) SELECT DATEADD(hh, 4, GETDATE()) INSERT INTO @tbEvents (startHour) SELECT DATEADD(hh, 5, GETDATE()) --SELECT * FROM @tbEvents DECLARE @startTime datetime SET @startTime = DATEADD(mi, 65, GETDATE()) SELECT timeEvent, CONVERT(time(0), startHour) AS 'startHour', CONVERT(time(0), @startTime) AS '@startTime' FROM @tbEvents WHERE CONVERT(time(0), startHour) >= CONVERT(time(0), @startTime)
if (cast('2012-06-20 23:49:14.363' as time) between cast('2012-06-20 23:49:14.363' as time) and cast('2012-06-20 23:49:14.363' as time))
одна (возможно, небольшая) проблема, которую я отметил с решениями до сих пор, заключается в том, что все они, похоже, требуют вызова функции для обработки сравнения. Это означает, что механизм запросов должен будет выполнить полное сканирование таблицы для поиска строк, которые вы ищете, и не сможет использовать индекс. Если таблица не будет особенно большой, это, вероятно, не будет иметь никаких неблагоприятных последствий (и вы можете с радостью игнорировать этот ответ).
Если, с другой стороны, таблица может быть довольно большой, производительность запроса может пострадать.
Я знаю, что вы заявили, что не хотите сравнивать часть даты - но есть ли фактическая дата, хранящаяся в столбце datetime, или вы используете ее для хранения только времени? Если последнее, вы можете использовать простой оператор сравнения, и это уменьшит использование ЦП и позволит механизму запросов использовать статистику и индексы (если они есть) для оптимизации запроса.
Если, однако, столбец datetime используется для хранения как дата и время события, это, очевидно, не будет работать. В этом случае, если вы можете изменить приложение и структуру таблицы, разделите дату и время на два отдельных столбца datetime или создайте индексированное представление, которое выбирает все (соответствующие) столбцы исходной таблицы и дополнительный столбец, содержащий элемент времени, который вы хотите найти (используйте любой из предыдущих ответов для вычисления этого) - и измените приложение для запроса представления вместо этого.
использование float не работает.
DECLARE @t1 datetime, @t2 datetime SELECT @t1 = '19000101 23:55:00', @t2 = '20001102 23:55:00' SELECT CAST(@t1 as float) - floor(CAST(@t1 as float)), CAST(@t2 as float) - floor(CAST(@t2 as float))
вы увидите, что значения не совпадают (SQL Server 2005). Я хотел использовать этот метод для проверки времени около полуночи (полный метод имеет более подробную информацию), в котором я сравнивал текущее время между 23:55:00 и 00:05:00.
просто измените преобразование даты и времени во время, которое должно сделать трюк:
SELECT timeEvent FROM tbEvents WHERE convert(time, startHour) >= convert(time, @startHour)
добавление к другим ответам:
вы можете создать функцию для обрезки даты из datetime
CREATE FUNCTION dbo.f_trimdate (@dat datetime) RETURNS DATETIME AS BEGIN RETURN CONVERT(DATETIME, CONVERT(FLOAT, @dat) - CONVERT(INT, @dat)) END
значит так:
DECLARE @dat DATETIME SELECT @dat = '20080201 02:25:46.000' SELECT dbo.f_trimdate(@dat)
вернутся 1900-01-01 02:25:46.000
использовать функцию Datepart: DATEPART(функция datepart, дата)
например#
выберите DatePart (@YourVar, hh)*60) + DatePart (@YourVar, mi)*60)
Это даст вам общее время суток в минутах, что позволит вам сравнить более легко.
вы можете использовать DateDiff, если ваши даты будут одинаковыми, в противном случае вам нужно будет удалить дату, как указано выше
SELECT timeEvent FROM tbEvents WHERE CONVERT(VARCHAR,startHour,108) >= '01:01:01'
это говорит SQL Server, чтобы преобразовать текущую дату / время в varchar, используя стиль 108, который является "hh:mm:ss". Вы также можете заменить '01:01:01', который еще конвертировать при необходимости.
Я не люблю полагаться на внутренние хранилища (что datetime-это поплавок с целым числом = день и дробным = время), но я делаю то же самое, что и ответ Jhonny D. Cano. Так делают все разработчики БД, которых я знаю. Определенно не преобразуйте в строку. Если вы должны избегать обработки как float / int, то лучший вариант-вытащить hour / minute / second / milliseconds с DatePart ()
Вы можете создать две переменные datetime и установить только час даты, которую вам нужно сравнить.
declare @date1 datetime; declare @date2 datetime; select @date1 = CONVERT(varchar(20),CONVERT(datetime, '2011-02-11 08:00:00'), 114) select @date2 = CONVERT(varchar(20),GETDATE(), 114)
дата будет "1900-01-01" вы можете сравнить это
if @date1 <= @date2 print '@date1 less then @date2' else print '@date1 more then @date2'
Я предполагаю, что ваш столбец startHour и переменная @startHour являются DATETIME; в этом случае вы должны преобразовать в строку:
SELECT timeEvent FROM tbEvents WHERE convert(VARCHAR(8), startHour, 8) >= convert(VARCHAR(8), @startHour, 8)
ниже запрос дает вам время даты
select DateAdd(day,-DateDiff(day,0,YourDateTime),YourDateTime) As NewTime from Table
@ronmurp вызывает обоснованное беспокойство - подход cast / floor возвращает разные значения за одно и то же время. По строкам ответа @littlechris и для более общего решения, которое решает для Раз, которые имеют минутный, секундный, миллисекундный компонент, вы можете использовать эту функцию для подсчета количества миллисекунд с начала дня.
Create Function [dbo].[MsFromStartOfDay] ( @DateTime datetime ) Returns int As Begin Return ( ( Datepart( ms , @DateTime ) ) + ( Datepart( ss , @DateTime ) * 1000 ) + ( Datepart( mi , @DateTime ) * 1000 * 60 ) + ( Datepart( hh , @DateTime ) * 1000 * 60 * 60 ) ) End
Я проверил, что он возвращает один и тот же int для двух разных дат с одинаковыми время
declare @first datetime set @first = '1900-01-01 23:59:39.090' declare @second datetime set @second = '2000-11-02 23:56:39.090' Select dbo.MsFromStartOfDay( @first ) Select dbo.MsFromStartOfDay( @second )
Это решение не всегда возвращает int, который вы ожидали бы. Например, попробуйте ниже в SQL 2005, он возвращает int, заканчивающийся на ' 557 'вместо ' 556'.
set @first = '1900-01-01 23:59:39.556' set @second = '2000-11-02 23:56:39.556'
Я думаю, что это связано с природой DateTime хранится как float. Вы все еще можете сравнить два числа, хотя. И когда я использовал этот подход на "реальном" наборе данных DateTime, захваченном в .NET, используя DateTime.Теперь() и хранится в SQL, я обнаружил, что вычисления были точный.