tipo - Fecha MS SQL solo sin tiempo
obtener mes y año de una fecha sql (12)
Pregunta
Hola a todos,
He tenido cierta confusión durante bastante tiempo con el uso de un tipo de SQL DateTime usando T-SQL. Esencialmente, quiero tomar un valor de DateTime de, por ejemplo, 2008-12-1 14:30:12 y hacerlo 2008-12-1 00:00:00. Muchas de las consultas que ejecutamos para los informes usan un valor de fecha en la cláusula WHERE, pero o bien tengo un valor de fecha de inicio y fin de un día y uso un BETWEEN, o encuentro otro método.
Actualmente estoy usando lo siguiente: WHERE CAST(CONVERT(VARCHAR, [tstamp], 102) AS DATETIME) = @dateParam
Sin embargo, esto parece un poco torpe. Esperaba que hubiera algo más simple como CAST([tstamp] AS DATE)
Algunos sitios en línea recomiendan usar la función DATEPART (), pero luego termino con algo como esto:
WHERE DATEPART(year, [tstamp]) = DATEPART(year, @dateParam)
AND DATEPART(month, [tstamp]) = DATEPART(month, @dateParam)
AND DATEPART(day, [tstamp]) = DATEPART(day, @dateParam)
Tal vez estoy demasiado preocupado por algo pequeño y, si es así, házmelo saber. Solo quiero asegurarme de que lo que estoy escribiendo sea lo más eficiente posible. Quiero eliminar cualquier enlace débil.
¿Alguna sugerencia?
Gracias,
do
Solución
Gracias a todos por los excelentes comentarios. Mucha información útil. Voy a cambiar nuestras funciones para eliminar la función en el lado izquierdo del operador. Aunque la mayoría de nuestras columnas de fecha no usan índices, probablemente sea una mejor práctica.
Cuidado aquí, si usa algo largo las líneas de WHERE CAST(CONVERT(VARCHAR, [tstamp], 102) AS DATETIME) = @dateParam
forzará un escaneo en la tabla y no se usarán índices para esa parte.
Una forma mucho más limpia de hacerlo es definir una columna calculada
create table #t (
d datetime,
d2 as
cast (datepart(year,d) as varchar(4)) + ''-'' +
right(''0'' + cast (datepart(month,d) as varchar(2)),2) + ''-'' +
right(''0'' + cast (datepart(day,d) as varchar(2)),2)
)
-- notice a lot of care need to be taken to ensure the format is comparable. (zero padding)
insert #t
values (getdate())
create index idx on #t(d2)
select d2, count(d2) from #t
where d2 between ''2008-01-01'' and ''2009-01-22''
group by d2
-- index seek is used
De esta manera, puede verificar directamente la columna d2 y se usará un índice y no tendrá que perder conversiones.
Las funciones de fecha publicadas por otros son la forma más correcta de manejar esto.
Sin embargo, es divertido que menciones el término "piso", porque hay un pequeño truco que se ejecutará un poco más rápido:
CAST(FLOOR(CAST(@dateParam AS float)) AS DateTime)
Sí, T-SQL puede sentirse extremadamente primitivo a veces, y son cosas como estas las que a menudo me empujan a hacer un montón de mi lógica en mi idioma de elección (como C #).
Sin embargo, cuando es absolutamente necesario hacer algunas de estas cosas en SQL por motivos de rendimiento, la mejor opción es crear funciones para alojar estos "algoritmos".
Mira este articulo. Él ofrece bastantes funciones prácticas de SQL en esta línea que creo que te ayudarán.
http://weblogs.sqlteam.com/jeffs/archive/2007/01/02/56079.aspx
eso es muy malo para el rendimiento, eche un vistazo a Solo en una base de datos ¿Puede obtener un 1000% de mejora al cambiar unas pocas líneas de código?
las funciones en el lado izquierdo del operador son malas
Aquí está lo que tú necesitas hacer
declare @d datetime
select @d = ''2008-12-1 14:30:12''
where tstamp >= dateadd(dd, datediff(dd, 0, @d)+0, 0)
and tstamp < dateadd(dd, datediff(dd, 0, @d)+1, 0)
Ejecuta esto para ver lo que hace
select dateadd(dd, datediff(dd, 0, getdate())+1, 0)
select dateadd(dd, datediff(dd, 0, getdate())+0, 0)
Alternativamente podrías usar
declare @d datetimeselect
@d = ''2008-12-1 14:30:12''
where tstamp
BETWEEN dateadd(dd, datediff(dd, 0, @d)+0, 0)
AND dateadd(dd, datediff(dd, 0, @d)+1, 0)
Aquí hay una consulta que devolverá todos los resultados dentro de un rango de días.
DECLARE @startDate DATETIME
DECLARE @endDate DATETIME
SET @startDate = DATEADD(day, -30, GETDATE())
SET @endDate = GETDATE()
SELECT *
FROM table
WHERE dateColumn >= DATEADD(day, DATEDIFF(day, 0, @startDate), 0)
AND dateColumn < DATEADD(day, 1, DATEDIFF(day, 0, @endDate))
¿Qué tal esto?
SELECT DATEADD(dd, DATEDIFF(dd,0,GETDATE()), 0)
FWIW, he estado haciendo lo mismo que tu durante años
CAST(CONVERT(VARCHAR, [tstamp], 102) AS DATETIME) = @dateParam
Me parece que esta es una de las mejores formas de perder tiempo en términos de flexibilidad, velocidad y facilidad de lectura. (lo siento). Algunas funciones UDF como se sugieren pueden ser útiles, pero las UDF pueden ser lentas con conjuntos de resultados más grandes.
CONVERT(date, GETDATE())
y CONVERT(time, GETDATE())
funciona en SQL Server 2008. No estoy seguro acerca de 2005.
WHERE DATEDIFF(day, tstamp, @dateParam) = 0
Esto debería llevarte allí si no te importa el tiempo.
Esto es para responder la meta pregunta de comparar las fechas de dos valores cuando no te importa el tiempo.
DATEADD(d, 0, DATEDIFF(d, 0, [tstamp]))
Editar: Si bien esto eliminará la porción de tiempo de su fecha y hora, también hará que la condición no sea SARGABLE . Si eso es importante para esta consulta, una vista indexada o una cláusula between es más apropiada.