obtener - tipo de dato date sql
Comparaciones de fechas de SQL Server basadas únicamente en meses y años (4)
Tengo problemas para determinar la mejor forma de comparar fechas en SQL en función del mes y el año solamente.
Hacemos cálculos basados en fechas y dado que la facturación ocurre mensualmente, la fecha del mes ha causado más obstáculos.
Por ejemplo
DECLARE @date1 DATETIME = CAST(''6/15/2014'' AS DATETIME),
@date2 DATETIME = CAST(''6/14/2014'' AS DATETIME)
SELECT * FROM tableName WHERE @date1 <= @date2
El ejemplo anterior no devolverá ninguna fila ya que @ date1 es mayor que @ date2. Entonces me gustaría encontrar una manera de sacar el día de la ecuación.
Del mismo modo, la siguiente situación me causa dolor por la misma razón.
DECLARE @date1 DATETIME = CAST(''6/14/2014'' AS DATETIME),
@date2 DATETIME = CAST(''6/15/2014'' AS DATETIME),
@date3 DATETIME = CAST(''7/1/2014'' AS DATETIME)
SELECT * FROM tableName WHERE @date2 BETWEEN @date1 AND @date3
He hecho conversiones en línea de las fechas para derivar el primer día y el último día del mes para la fecha especificada.
SELECT *
FROM tableName
WHERE date2 BETWEEN
DATEADD(month, DATEDIFF(month, 0, date1), 0) -- The first day of the month for date1
AND
DATEADD(s, -1, DATEADD(mm, DATEDIFF(m, 0, date2) + 1, 0)) -- The lastday of the month for date3
Tiene que haber una manera más fácil de hacer esto. ¿Alguna sugerencia?
Para manejar las desigualdades, como entre, me gusta convertir la fecha / hora a una representación YYYYMM, ya sea como una cadena o un número entero. Para este ejemplo:
DECLARE @date1 DATETIME = CAST(''6/14/2014'' AS DATETIME),
@date2 DATETIME = CAST(''6/15/2014'' AS DATETIME),
@date3 DATETIME = CAST(''7/1/2014'' AS DATETIME);
SELECT * FROM tableName WHERE @date2 BETWEEN @date1 AND @date3;
Escribiría la consulta como:
SELECT *
FROM tableName
WHERE year(@date2) * 100 + month(@date2) BETWEEN year(@date1) * 100 + month(@date1) AND
year(@date3) * 100 + month(@date1);
Primero, usaría un formato para las fechas que no sea ambiguo, como el estándar ''YYYYMMDD''
y no el ''6/15/2014''
que ha estado usando. El blog de Aaron Bertrand explica mucho mejor que yo, las diversas formas en que esto puede ir mal:
Malos hábitos a patear: consultas de rango / fecha incorrectas
Para el problema específico, su última consulta, que encuentra el primer y el último día de los meses (para date1 y date3), en mi opinión está en el camino correcto. Solo necesita los primeros días de meses (el primer día de la fecha1 y el primer día del próximo mes para la fecha3), si evita el mal BETWEEN
: ¿Qué tienen en común BETWEEN y el diablo?
SELECT *
FROM tableName
WHERE date2 >= DATEADD(month, DATEDIFF(month, ''19000101'', @date1), ''19000101'')
AND date2 < DATEADD(month, 1+DATEDIFF(month, ''19000101'', @date3), ''19000101'') ;
La consulta funciona tal como está, sin importar el tipo de datos de date2
( DATE
, DATETIME
, DATETIME2
o SMALLDATTEIME
).
El optimizador considerará los puntos de bonificación, los índices en date2
esta manera.
Mejora, de acuerdo con (aún, otra) publicación de Aaron en el blog, para evitar un problema con la estimación de cardinalidad al evaluar expresiones con DATEDIFF()
:
Sorpresas y suposiciones de rendimiento: DATEDIFF
SELECT *
FROM tableName
WHERE date2 >= CONVERT(DATE, DATEADD(day, 1 - DAY(@date1), @date1))
AND date2 < DATEADD(month, 1,
CONVERT(DATE, DATEADD(day, 1 - DAY(@date3), @date3))) ;
Puede filtrar el mes y el año de una fecha determinada a la fecha actual así:
SELECT *
FROM tableName
WHERE month(date2) = month(getdate()) and year(date2) = year(getdate())
Simplemente reemplace el método GETDATE()
con la fecha deseada.