Как я могу сравнить время в SQL Server?
Я пытаюсь сравнить время в поле datetime в SQL-запросе, но я не знаю, как это правильно. Я не хочу сравнивать дату, часть времени.
Я делаю это:
SELECT timeEvent
FROM tbEvents
WHERE convert(datetime, startHour, 8) >= convert(datetime, @startHour, 8)
Правильно ли это?
Я спрашиваю об этом, потому что мне нужно знать, если '08: 00: 00 'меньше или больше, чем '07: 30: 00', и я не хочу сравнивать дату, только часть времени.
Спасибо!
Ответы
Ответ 1
Ваше сравнение будет работать, но оно будет медленным, потому что даты преобразуются в строку для каждой строки. Чтобы эффективно сравнить две части времени, попробуйте:
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-сервере хранится как число с плавающей запятой. Цифры до десятичной точки представляют собой дату. Цифры после десятичной точки представляют время.
Итак, вот пример даты:
declare @mydate datetime
set @mydate = '2009-04-30 19:47:16.123'
Позвольте преобразовать его в float:
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 довольно быстры, потому что они в основном хранятся одинаково.
Ответ 2
convert(varchar(5), thedate, 108) between @leftTime and @rightTime
Пояснение:
если у вас есть varchar(5)
, вы получите HH:mm
если у вас есть varchar(8)
, вы получаете HH:mm ss
108 получает только время от даты SQL
@leftTime
и @rightTime
- две переменные для сравнения
Ответ 3
Если вы используете 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)
Ответ 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))
Ответ 5
Одна (возможно, небольшая) проблема, о которой я уже говорил с решениями, заключается в том, что все они требуют вызова функции для обработки сравнения. Это означает, что движок запроса должен будет выполнить полное сканирование таблицы для поиска строк, которые вы после - и не сможете использовать индекс. Если таблица не будет особенно большой, это, вероятно, не будет иметь никаких негативных последствий (и вы можете с радостью проигнорировать этот ответ).
Если, с другой стороны, таблица может стать довольно большой, производительность запроса может пострадать.
Я знаю, что вы заявили, что не хотите сравнивать дату, но есть ли фактическая дата, хранящаяся в столбце datetime, или вы используете ее для хранения только времени? Если последнее, вы можете использовать простой оператор сравнения, и это уменьшит использование ЦП и позволит механизму запросов использовать статистику и индексы (если они есть) для оптимизации запроса.
Если, однако, столбец datetime используется для хранения как даты, так и времени события, это явно не сработает. В этом случае, если вы можете изменить приложение и структуру таблицы, разделите дату и время на два отдельных столбца datetime или создайте индексированное представление, которое будет выбирать все (соответствующие) столбцы исходной таблицы, а также следующий столбец, содержащий который вы хотите найти (используйте любой из предыдущих ответов, чтобы вычислить это) - и измените приложение, чтобы запросить представление.
Ответ 6
Использование 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.
Ответ 7
Использовать функцию Datepart: DATEPART (datepart, date)
например #
SELECT DatePart (@YourVar, hh) * 60) + DatePart (@YourVar, mi) * 60)
Это даст вам общее время дня в минутах, что позволит вам легко сравнивать.
Вы можете использовать DateDiff, если ваши даты будут одинаковыми, иначе вам нужно будет удалить дату, указанную выше
Ответ 8
Добавление к другим ответам:
вы можете создать функцию для обрезки даты из 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
Ответ 9
Просто измените дату и время преобразования, чтобы сделать трюк:
SELECT timeEvent
FROM tbEvents
WHERE convert(time, startHour) >= convert(time, @startHour)
Ответ 10
Я считаю, что вы хотите использовать DATEPART('hour', datetime)
.
Ссылка здесь:
http://msdn.microsoft.com/en-us/library/ms174420.aspx
Ответ 11
Мне не нравится полагаться на внутренности хранилища (это дата и время - это float с целым числом = день и дробное = время), но я делаю то же самое, что и ответ Джонни Д. Кано. Именно так я знаю всех разработчиков db. Определенно не конвертировать в строку. Если вы не должны обрабатывать как float/int, то лучшим вариантом является вытащить час/минуту/секунду/миллисекунды с помощью DatePart()
Ответ 12
Вы можете создать две переменные 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'
Ответ 13
SELECT timeEvent
FROM tbEvents
WHERE CONVERT(VARCHAR,startHour,108) >= '01:01:01'
Это говорит SQL Server, чтобы преобразовать текущую дату/время в varchar, используя стиль 108, который является "hh: mm: ss". Вы также можете заменить '01: 01: 01 ', который при необходимости преобразует другое.
Ответ 14
Я предполагаю, что ваш столбец startHour и переменная @startHour равны DATETIME; В этом случае вы должны преобразовать строку:
SELECT timeEvent
FROM tbEvents
WHERE convert(VARCHAR(8), startHour, 8) >= convert(VARCHAR(8), @startHour, 8)
Ответ 15
ниже запрос дает вам время даты
select DateAdd(day,-DateDiff(day,0,YourDateTime),YourDateTime) As NewTime from Table
Ответ 16
@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.Now() и хранящемся в SQL, я обнаружил, что вычисления были точными.