2011-09-13 17 views
5

¿Es posible escribir una consulta de Microsoft SQL que se agrupe por un tipo de datos datetime pero ignorando la parte de hora como la hora y el minuto?Agrupar por fecha y hora ignorar la parte

+2

¿Qué versión de SQL Server? Importa para esta pregunta en particular. (es * posible * en todas las versiones de SQL Server, pero hay una mejor solución en 2008+) – RBarryYoung

+0

posible duplicado de [Cómo truncar una fecha y hora en SQL Server] (http://stackoverflow.com/questions/923295/ how-to-truncate-a-datetime-in-sql-server) y [muchos otros] (http://www.google.com/cse?cx=018205968162215846785%3A7n6ajnwyz-i&ie=UTF-8&q=sql+server+ truncate +% 28datetime | time% 29 & sa = Search & siteurl = www.google.com% 2Fcse% 2Fhome% 3Fcx% 3D018205968162215846785% 3A7n6ajnwyz-i) –

+1

@AndriyM - Agrupar por la parte 'date' de' datetime' presenta un problema de optimización específico más allá de solo truncar la parte de la fecha. p.ej. comparar los planes para 'CREAR TABLA T1 (D DATETIME2 PRIMARY KEY); CREAR TABLA T2 (D DATE, T TIME, PRIMARY KEY (D, T)); SELECCIONAR COUNT (*) FROM T1 GROUP BY CAST (D AS DATE) OPCIÓN (GRUPO DE PEDIDO); SELECCIONE CUENTA (*) DEL GRUPO T2 POR D OPCIÓN (GRUPO DE PEDIDOS) ' –

Respuesta

12

Si está en SQL Server 2008, esto es simple.

GROUP BY CAST(YourCol AS Date) 

Para las versiones anteriores se puede utilizar

GROUP BY DATEDIFF(DAY, 0, YourCol) 

Sin embargo ninguno de ellos será capaz de aprovechar el hecho de que un índice en YourCol que es ordenado por datetime también se ordenarán por date y por lo tanto utilizar un agregado de flujo sin una operación de clasificación.

En SQL Server 2008+ puede considerar indexar (date,time) en lugar de datetime para facilitar este tipo de consulta.

Ya sea por simplemente almacenarla como dos componentes separados y posiblemente proporcionar una columna calculada que se recombina las partes (a datetime2 se almacena el mismo que una date y una time por lo que este no consumirá más espacio excepto si el adicional la columna empuja el NULL_BITMAP en un nuevo byte).

CREATE TABLE T 
(
YourDateCol date, 
YourTimeCol time, 
YourDateTimeCol AS DATEADD(day, 
          DATEDIFF(DAY,0,YourDateCol), 
          CAST(YourTimeCol AS DATETIME2(7))) 
/*Other Columns*/ 
) 

O, alternativamente, se podría almacenar combinó en la tabla de base y tienen los índices calculados utilizan columnas que dividen a cabo.

Un ejemplo de este enfoque

CREATE TABLE T 
(
DT DATETIME2, 
D AS CAST(DT AS DATE), 
T AS CAST(DT AS TIME) 
) 

CREATE INDEX IX1 ON T(DT); 

SELECT COUNT(*), 
     CAST(DT AS DATE) 
FROM T 
GROUP BY CAST(DT AS DATE) 

CREATE INDEX IX2 ON T(D,T); 

SELECT COUNT(*), 
     CAST(DT AS DATE) 
FROM T 
GROUP BY CAST(DT AS DATE) 

DROP TABLE T 

enter image description here

+3

'GROUP BY DATEDIFF (DAY, 0, YourCol)' probablemente también sea suficiente en este caso ... – Tomalak

+0

@Tomalak - Buen punto. Eso devolverá un 'int' que es suficiente para' group by' y no hay razón para convertir de nuevo a 'datetime' excepto para fines de visualización. –

1

Si usted tiene una mesa grande y desea agrupar a suceder rápido, no se puede confiar en la agrupación de una expresión.

Crear una columna de fecha y hora adicional en su mesa y lo han llenado por un disparador que calcula la fecha de base desde la que "real" fecha:

UPDATE 
    MyTable 
SET 
    EffectiveDate = DATEADD(DAY, 0, DATEDIFF(DAY, 0, t.RecordDate)) 
FROM 
    MyTable t 
    INNER JOIN inserted i ON i.RowID = t.RowID 

a continuación, poner un índice en EffectiveDate y agrupar (y búsqueda) será mucho más rápido.

+0

Para el lanzamiento de SQL Server 2008 por fecha [es sargable] (http://connect.microsoft.com/SQLServer/feedback/details/526431/make-more-functions-sargable) aunque no he comprobado si esto se aprovecha en 'group by' consultas. –

+0

@Martin Interesante, no lo sabía. Pero todavía activaría un escaneo de tabla cuando no hay un índice en la columna, ¿no es así? – Tomalak

+0

¿Por qué un disparador y no una columna calculada? 'EffectiveDate COMO CONVERTIR (DATETIME, DATEADD (DAY, 0, DATEDIFF (DAY, 0, t.RecordDate)))' - esta columna podría ser persistente e indexada también para eliminar cualquier duda sobre la sargabilidad, sin pagar la sobrecarga de un desencadenar. –

Cuestiones relacionadas