2009-04-30 6 views
49

Я пытаюсь сравнить время в поле datetime в SQL-запросе, но я не знаю, что это правильно. Я не хочу сравнивать дату, часть времени.Как сравнить время в SQL Server?

Я делаю это:

SELECT timeEvent 
FROM tbEvents 
WHERE convert(datetime, startHour, 8) >= convert(datetime, @startHour, 8) 

Является ли это правильно?

Я спрашиваю об этом, потому что мне нужно знать, если '08: 00: 00 'меньше или больше, чем '07: 30: 00', и я не хочу сравнивать дату, только часть времени.

Спасибо!

+0

Почему я должен преобразовать в VARCHAR, так что я могу сравнить, если время больше, чем другой? Разве я не сравню строку со строкой? – AndreMiranda

+0

Функция DateDiff принимает поля datetime в качестве входных данных, так что вы получите над горбом. – Eric

ответ

69

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

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 

Long Объяснение: дата в сервере SQL хранится в виде числа с плавающей точкой. Цифры до десятичной точки представляют собой дату. Цифры после десятичной точки представляют время.

Так вот дата пример:

declare @mydate datetime 
set @mydate = '2009-04-30 19:47:16.123' 

Давайте преобразуем его к поплавку:

declare @myfloat float 
set @myfloat = cast(@mydate as float) 
select @myfloat 
-- Shows 39931,8244921682 

Теперь возьмите часть после цифры, т.е. время:

set @myfloat = @myfloat - floor(@myfloat) 
select @myfloat 
-- Shows 0,824492168212601 

Преобразуйте его обратно в дату и время:

declare @mytime datetime 
set @mytime = convert(datetime,@myfloat) 
select @mytime 
-- Shows 1900-01-01 19:47:16.123 

1900-01-01 - это только «нулевая» дата; Вы можете отобразить часть времени с новообращенным, указав, например, формат 108, который только время:

select convert(varchar(32),@mytime,108) 
-- Shows 19:47:16 

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

+0

Это замечательно, спасибо! Я делаю много преобразования varchar, это кажется лучшим способом (хотя не сразу очевидным, если смотреть на него). – Alex

2

Использование DATEPART функции: DATEPART (DatePart, дата)

Например #

ВЫБРАТЬ DatePart (@YourVar, чч) * 60) + DatePart (@YourVar, мили) * 60)

Это даст вам общее время суток в минутах, что позволит вам легко сравнивать.

Вы можете использовать DATEDIFF, если ваши даты будет такой же, в противном случае вам нужно вырезать дату, как указано выше

0
SELECT timeEvent 
    FROM tbEvents 
WHERE CONVERT(VARCHAR,startHour,108) >= '01:01:01' 

Это говорит SQL Server для преобразования текущей даты/времени в varchar, используя стиль 108, который является «hh: mm: ss». Вы также можете заменить '01: 01: 01 ', который при необходимости преобразует другое.

0

Я предполагаю, что ваша колонка StartHour и переменная @startHour оба DATETIME; В этом случае, вы должны преобразовать в строку:

SELECT timeEvent 
FROM tbEvents 
WHERE convert(VARCHAR(8), startHour, 8) >= convert(VARCHAR(8), @startHour, 8) 
+0

Крис, почему мне нужно преобразовать в VARCHAr, чтобы сравнить время? Таким образом, не будет ли я сравнивать строку со строкой? – AndreMiranda

+1

Две причины - 1) Метод CONVERT() предназначен для преобразования из одного типа в другой; Если вы конвертируете DATETIME в DATETIME, ничего не происходит. 2) Третий параметр CONVERT() (8) - это код для форматирования данных при переходе к типу строки; Это не имеет никакого значения при преобразовании в DATETIME. –

2

Добавление в другие ответы:

вы можете создать функцию для обрезки дату от даты-времени

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 2:25:46.000

+0

литье в раунды INT, что сделало бы результат не всегда точным, FLOOR - это путь – murki

+0

Вот почему образец: округление по дате, поэтому мы можем работать только на поле времени. Вы проверили это? –

11

Если вы используете 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) 
+0

Роб, я использую 2005 :-( – AndreMiranda

+0

Спасибо, Роб, «DATEADD» был тем, что я искал! – Neville

17
convert(varchar(5), thedate, 108) between @leftTime and @rightTime 

Объяснение:

если у вас есть varchar(5) вы получите HH:mm

если у вас есть varchar(8) вы получаете HH:mm ss

108 получает только время от даты SQL

@leftTime и @rightTime являются две переменные для сравнения

+0

мне тоже помогает :). – 2009-05-02 10:31:25

1

Я не люблю полагаться на внутренности хранилища (что datetime является поплавком с целым числом = день и дробное = время), но я делаю то же самое, что и ответ Jhonny D. Cano. Именно так я знаю всех разработчиков db. Определенно не конвертировать в строку. Если вы не должны обрабатывать как float/int, то лучшим вариантом является вытащить часы/минуту/секунду/миллисекунды с помощью DatePart()

3

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

Если, с другой стороны, таблица может стать довольно большой, производительность запроса может пострадать.

Я знаю, что вы заявили, что не хотите сравнивать дату, но есть ли фактическая дата, хранящаяся в столбце datetime, или вы используете ее для хранения только времени? Если последнее, вы можете использовать простой оператор сравнения, и это уменьшит использование ЦП и позволит механизму запросов использовать статистику и индексы (если они есть) для оптимизации запроса.

Если, однако, столбец datetime используется для хранения как даты, так и времени события, это явно не сработает. В этом случае, если вы можете изменить приложение и структуру таблицы, разделите дату и время на два отдельных столбца datetime или создайте индексированное представление, которое будет выбирать все (соответствующие) столбцы исходной таблицы, а также следующий столбец, содержащий который вы хотите найти (используйте любой из предыдущих ответов, чтобы вычислить это) - и измените приложение, чтобы запросить представление вместо этого.

3

Использование поплавка не работает.

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.

1

Вы можете создать две переменные 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' 
0

ниже запроса дает время дня

select DateAdd(day,-DateDiff(day,0,YourDateTime),YourDateTime) As NewTime from Table 
4
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)) 
0

@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) 

Это решение не всегда возвращает ИНТ можно было бы ожидать. Например, попробуйте ниже в 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.Now() и хранящемся в SQL, я обнаружил, что вычисления были точными.

+0

примечание - производительность, похоже, не очень хороша при таком подходе – SFun28

2

Просто измените преобразования DateTime ко времени, которое должно сделать трюк:

SELECT timeEvent 
FROM tbEvents 
WHERE convert(time, startHour) >= convert(time, @startHour) 
Смежные вопросы