Estoy tratando de agrupar registros por semana, almacenando la fecha agregada como el primer día de la semana. Sin embargo, la técnica estándar que utilizo para redondear fechas no parece funcionar correctamente con semanas (aunque sí lo hace con días, meses, años, trimestres y cualquier otro período de tiempo al que lo haya aplicado).
Aquí está el SQL:
select "start_of_week" = dateadd(week, datediff(week, 0, getdate()), 0);
Esto vuelve 2011-08-22 00:00:00.000
, que es un lunes, no un domingo. Al seleccionar @@datefirst
devoluciones 7
, que es el código del domingo, para que el servidor esté configurado correctamente hasta donde yo sé.
Puedo omitir esto con bastante facilidad cambiando el código anterior a:
select "start_of_week" = dateadd(week, datediff(week, 0, getdate()), -1);
Pero el hecho de que tenga que hacer tal excepción me inquieta un poco. Además, disculpas si esta es una pregunta duplicada. Encontré algunas preguntas relacionadas, pero ninguna que abordara este aspecto específicamente.
fuente
(@@DATEFIRST + DATEPART(DW, @SomeDate)) % 7
permanece constante independientemente del@@datefirst
entorno, creo. Con lunes = 2.Respuestas:
Para responder por qué tiene un lunes y no un domingo:
Está agregando un número de semanas a la fecha 0. ¿Qué es la fecha 0? 1900-01-01. ¿Qué día fue el 01/01/1900? Lunes. Entonces, en su código está diciendo, ¿cuántas semanas han pasado desde el lunes 1 de enero de 1900? Llamemos a eso [n]. Bien, ahora agregue [n] semanas al lunes 1 de enero de 1900. No debería sorprenderse de que termine siendo lunes.
DATEADD
no tiene idea de que desea agregar semanas, pero solo hasta que llegue un domingo, solo agrega 7 días, luego agrega 7 días más, ... al igual queDATEDIFF
solo reconoce los límites que se han cruzado. Por ejemplo, ambos devuelven 1, aunque algunas personas se quejan de que debería haber alguna lógica sensata incorporada para redondear hacia arriba o hacia abajo:Para responder cómo conseguir un domingo:
Si desea un domingo, elija una fecha base que no sea un lunes sino un domingo. Por ejemplo:
Esto no se interrumpirá si cambia su
DATEFIRST
configuración (o su código se está ejecutando para un usuario con una configuración diferente), siempre que aún desee un domingo independientemente de la configuración actual. Si quieres esas dos respuestas a jive, entonces usted debe utilizar una función que no dependen de laDATEFIRST
configuración, por ejemplo,Entonces, si cambia su
DATEFIRST
configuración a lunes, martes, lo que sea, el comportamiento cambiará. Según el comportamiento que desee, puede utilizar una de estas funciones:...o...
Ahora, tiene muchas alternativas, pero ¿cuál funciona mejor? Me sorprendería si hubiera diferencias importantes, pero recopilé todas las respuestas proporcionadas hasta ahora y las ejecuté a través de dos conjuntos de pruebas: una barata y otra costosa. Medí las estadísticas del cliente porque no veo que la E / S o la memoria desempeñen un papel en el rendimiento aquí (aunque pueden entrar en juego dependiendo de cómo se use la función). En mis pruebas los resultados son:
Consulta de asignación "barata":
Consulta de asignación "cara":
Puedo transmitir los detalles de mis pruebas si lo deseo, deteniéndome aquí, ya que esto ya se está volviendo bastante largo. Me sorprendió un poco ver a Curt salir como el más rápido en el extremo superior, dada la cantidad de cálculos y el código en línea. Tal vez haga algunas pruebas más exhaustivas y escribo un blog al respecto ... si ustedes no tienen ninguna objeción a que publique sus funciones en otro lugar.
fuente
Para estos que necesitan obtener:
Lunes = 1 y domingo = 7:
Domingo = 1 y sábado = 7:
Arriba había un ejemplo similar, pero gracias al doble "% 7" sería mucho más lento.
fuente
select (datediff(dd,5,cal.D_DATE)%7 + 1)
yselect (datediff(dd,6,cal.D_DATE)%7 + 1)
Para aquellos que necesitan la respuesta en el trabajo y la función de creación está prohibida por su DBA, la siguiente solución funcionará:
Esto da el comienzo de esa semana. Aquí asumo que los domingos son el comienzo de las semanas. Si cree que el lunes es el comienzo, debe usar:
fuente
Esto funciona maravillosamente para mí:
fuente
Busqué en Google este script:
http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=47307
fuente
Quizás necesites esto:
O
Función
fuente
DATEPART(DW
depende de@@datefirst
DATE
entonces no tiene que hacer ninguna conversión subóptima ayVARCHAR
viceversa solo para eliminar cualquier componente de tiempo accidental que se haya pasado?Time
valores.fuente
Para lo básico (el domingo de la semana actual)
Si la semana anterior:
Internamente, creamos una función que lo hace, pero si lo necesita rápido y sucio, esto lo hará.
fuente
Dado que la fecha juliana 0 es un lunes, simplemente agregue el número de semanas al domingo, que es el día anterior a -1. seleccionar fechaadd (semana, fechadif (semana, 0, obtener fecha ()), - 1)
fuente
Esta es mi lógica. Establezca el primer día de la semana para que sea el lunes, luego calcule cuál es el día de la semana en un día determinado, luego, usando DateAdd y Case, calculo cuál habría sido la fecha el lunes anterior de esa semana.
fuente
No tengo ningún problema con ninguna de las respuestas que se dan aquí, sin embargo, creo que la mía es mucho más sencilla de implementar y comprender. No he realizado ninguna prueba de rendimiento en él, pero debería ser despreciable.
Entonces, obtuve mi respuesta del hecho de que las fechas se almacenan en el servidor SQL como números enteros (estoy hablando solo del componente de fecha). Si no me cree, intente esto SELECT CONVERT (INT, GETDATE ()), y viceversa.
Ahora, sabiendo esto, puedes hacer algunas ecuaciones matemáticas geniales. Es posible que se te ocurra uno mejor, pero aquí está el mío.
fuente
@@DATEFIRST
también es 7, pero si tu@testDate
es el comienzo de la semana, esto devuelve una fecha que es el día anterior.Tuve un problema similar. Dada una fecha, quería obtener la fecha del lunes de esa semana.
Usé la siguiente lógica: Encuentre el número de día de la semana en el rango de 0-6, luego reste eso de la fecha de origen.
Usé: DATEADD (día, - (DATEPART (día de la semana,) + 5)% 7,)
Dado que DATEPRRT (día de la semana,) devuelve 1 = domingo ... 7 = sábado, DATEPART (día de la semana,) + 5)% 7 devuelve 0 = lunes ... 6 = domingo.
Restando este número de días de la fecha original, se obtiene el lunes anterior. La misma técnica se puede utilizar para cualquier día de inicio de la semana.
fuente
Encontré esto simple y útil. Funciona incluso si el primer día de la semana es domingo o lunes.
DECLARAR @BaseDate como fecha
SET @BaseDate = GETDATE ()
DECLARAR @FisrtDOW COMO Fecha
SELECT @FirstDOW = DATEADD (d, DATEPART (WEEKDAY, @ BaseDate) * -1 + 1, @BaseDate)
fuente
Quizás estoy simplificando demasiado aquí, y ese puede ser el caso, pero esto parece funcionar para mí. No he tenido ningún problema con él todavía ...
fuente
SET DATEFIRST
.DATEFIRST
nada (desde hace tres años y medio), y todavía no lo hace. Y usted debe también evitar los formatos regionales comom/d/y
, incluso en escenarios donde el m y D son los mismos.