2009-04-30 65 views
49

Estoy tratando de comparar el tiempo en un campo de fecha y hora en una consulta SQL, pero no lo sé, es correcto. No quiero comparar la parte de la fecha, solo la parte del tiempo.¿Cómo puedo comparar el tiempo en SQL Server?

que estoy haciendo esto:

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

¿Es correcto?

Pregunto esto porque necesito saber si '08: 00: 00 'es menor o mayor que '07: 30: 00' y no quiero comparar la fecha, solo la parte de tiempo.

Gracias!

+0

¿Por qué tengo que convertir a VARCHAR así que puedo comparar si un tiempo es mayor que el otro? ¿No compararía esto la cuerda con la cuerda? – AndreMiranda

+0

La función DateDiff acepta campos de fecha y hora como entrada, por lo que le permitirá superar la barrera. – Eric

Respuesta

69

Su comparar va a funcionar, pero será lento porque las fechas se convierten en una cadena para cada fila. Para comparar dos partes de manera eficiente en tiempo, trate de:

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 

explicación larga: una fecha en el servidor SQL se almacena como un número de coma flotante. Los dígitos antes del punto decimal representan la fecha. Los dígitos después del punto decimal representan el tiempo.

así que aquí tiene una fecha de ejemplo:

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

Vamos a convertirlo en un flotador:

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

Ahora toma la parte después del dígito, es decir el tiempo:

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

Convertirlo a una fecha y hora:

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

El 1900-01-01 es solo la fecha "cero"; puede visualizar la pieza del tiempo con convert, especificando, por ejemplo, el formato 108, que está justo en el momento:

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

Las conversiones entre fecha y hora y el flotador son bastante rápido, porque están básicamente almacenan en la misma forma.

+0

Esto es genial, gracias! He estado haciendo una gran cantidad de conversión varchar, esto parece una mejor manera (aunque no es inmediatamente obvio al mirarlo). – Alex

2

Uso DATEPART función: DATEPART (datepart, fecha)

EG #

SELECT DatePart (@YourVar, hh) * 60) + DatePart (@YourVar, mi) * 60)

Esto le dará el tiempo total del día en minutos, lo que le permite comparar más fácilmente.

Puede utilizar DifFecha si las fechas van a ser los mismos, de lo contrario tendrá que tira a la fecha que el anterior

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

Esto indica a SQL Server para convertir la fecha/hora actual en una varchar usando el estilo 108, que es "hh: mm: ss". También puede reemplazar '01: 01: 01 ', que otro convertirá si es necesario.

0

Estoy asumiendo que su columna startHour y variables @startHour son tanto DATETIME; En ese caso, usted debe estar convirtiendo en una cadena:

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

Chris, ¿por qué tengo que convertir a VARCHAr para comparar los horarios? De esta manera, ¿no compararía una cuerda con una cuerda? – AndreMiranda

+1

Dos razones: 1) El método CONVERT() pretende convertir de un tipo a otro; Si CONVIERTE un DATETIME a DATETIME, no sucede nada. 2) El tercer parámetro para CONVERT() (el 8) es un código para formatear datos cuando se va a un tipo de cadena; No tiene ningún significado cuando se convierte a DATETIME. –

2

Agregando a las otras respuestas:

puede crear una función para el ajuste de la fecha a partir de una fecha y hora

CREATE FUNCTION dbo.f_trimdate (@dat datetime) RETURNS DATETIME AS BEGIN 
    RETURN CONVERT(DATETIME, CONVERT(FLOAT, @dat) - CONVERT(INT, @dat)) 
END 

Así que este :

DECLARE @dat DATETIME 
SELECT @dat = '20080201 02:25:46.000' 
SELECT dbo.f_trimdate(@dat) 

Will volver 1900-01-01 02:25:46.000

+0

lanzando a rondas INT, lo que haría que el resultado no siempre sea exacto, FLOOR es el camino a seguir – murki

+0

Ese es el motivo de la muestra: redondear en base a la fecha, para que podamos trabajar solo en el campo de tiempo. ¿Lo has probado? –

11

Si está utilizando SQL Server 2008, puede hacer esto:

WHERE CONVERT(time(0), startHour) >= CONVERT(time(0), @startTime) 

Aquí es una prueba completa:

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

Rob, estoy usando 2005 :-( – AndreMiranda

+0

Gracias Rob, el "DATEADD" era lo que estaba buscando! – Neville

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

Explicación:

si tiene varchar(5) obtendrá HH:mm

si tiene varchar(8) que obtener HH:mm ss

108 obtiene sólo el tiempo desde la fecha de SQL

@leftTime y @rightTime son dos variables para comparar

+0

me ayuda a mí también :). –

1

No me gusta depender de elementos internos de almacenamiento (esa fecha es un flotador con número entero = día y fracción = tiempo), pero hago lo mismo que la respuesta Jhonny D. Cano. Esta es la forma en que todos los desarrolladores de db que conozco lo hacen. Definitivamente no convertir a cadena. Si debe evitar el procesamiento como float/int, entonces la mejor opción es sacar hour/minute/second/miliseconds con DatePart()

3

Un problema (posiblemente pequeño) que he notado con las soluciones hasta el momento es que todos parecen requerir una llamada de función para procesar la comparación. Esto significa que el motor de consultas deberá realizar un escaneo completo de la tabla para buscar las filas que está buscando y no podrá usar un índice. Si la tabla no va a ser particularmente grande, probablemente no tenga ningún efecto adverso (y felizmente puede ignorar esta respuesta).

Si, por otro lado, la tabla puede llegar a ser bastante grande, el rendimiento de la consulta podría verse afectado.

Sé que usted indicó que no desea comparar la parte de la fecha, pero ¿hay una fecha real almacenada en la columna de fecha y hora o la está usando para almacenar solo la hora? En este último caso, puede utilizar un operador de comparación simple, lo que reducirá el uso de la CPU y permitirá que el motor de consulta use estadísticas e índices (si están presentes) para optimizar la consulta.

Sin embargo, si la columna de fecha y hora se usa para almacenar tanto la fecha como la hora del evento, obviamente esto no funcionará. En este caso, si puede modificar la aplicación y la estructura de la tabla, separe la fecha y la hora en dos columnas separadas de fecha y hora o cree una vista indizada que seleccione todas las columnas (relevantes) de la tabla fuente y una columna adicional que contenga el elemento de tiempo que desea buscar (use cualquiera de las respuestas anteriores para calcular esto) y modifique la aplicación para consultar la vista en su lugar.

3

El uso del flotador no funciona.

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

Verá que los valores no son los mismos (SQL Server 2005). Quería utilizar este método para verificar las horas alrededor de la medianoche (el método completo tiene más detalles) en el que comparé la hora actual de entre las 23:55:00 y las 00:05:00.

1

Puede crear dos variables de datetime y establecer solo la hora de la fecha que necesita comparar.

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) 

La fecha será "1900-01-01" se puede comparar

if @date1 <= @date2 
    print '@date1 less then @date2' 
else 
    print '@date1 more then @date2' 
0

debajo consulta le da tiempo a la fecha

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

aumentos @ronmurp una preocupación válida: el enfoque de reparto/piso arroja valores diferentes para el mismo tiempo. En la línea de la respuesta de @littlechris y para una solución más general que resuelve los tiempos que tienen un componente de minutos, segundos y milisegundos, puede usar esta función para contar la cantidad de milisegundos desde el comienzo del día.

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 

He verificado que devuelve el mismo int por dos fechas diferentes con el mismo tiempo

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) 

Esta solución no siempre devuelve el int que cabría esperar. Por ejemplo, intente lo siguiente en SQL 2005, devuelve una terminación int en '557' en lugar de '556'.

set @first = '1900-01-01 23:59:39.556' 
set @second = '2000-11-02 23:56:39.556' 

Creo que esto tiene que ver con la naturaleza de DateTime almacenada como flotante. Sin embargo, puedes comparar los dos números. Y cuando utilicé este enfoque en un conjunto de datos "real" de DateTime capturado en .NET usando DateTime.Now() y almacenado en SQL, encontré que los cálculos eran precisos.

+0

nota - el rendimiento parece no ser tan bueno con este enfoque – SFun28

2

acaba de cambiar de fecha y hora a convertir el tiempo que debe hacer el truco:

SELECT timeEvent 
FROM tbEvents 
WHERE convert(time, startHour) >= convert(time, @startHour) 
Cuestiones relacionadas