sql >> Base de Datos >  >> RDS >> Sqlserver

Obtenga el primer día de la semana en SQL Server

Para responder por qué recibe un lunes y no un domingo:

Estás agregando un número de semanas a la fecha 0. ¿Qué es la fecha 0? 1900-01-01. ¿Cuál fue el día el 1900-01-01? 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]. Ok, ahora agregue [n] semanas al lunes 1 de enero de 1900. No debería sorprenderse de que esto termine siendo un lunes. DATEADD no tiene idea de que desea agregar semanas, pero solo hasta que llegue a un domingo, solo agrega 7 días, luego agrega 7 días más, ... al igual que DATEDIFF solo reconoce los límites que se han cruzado. Por ejemplo, ambos devuelven 1, aunque algunas personas se quejan de que debería haber una lógica sensata incorporada para redondear hacia arriba o hacia abajo:

SELECT DATEDIFF(YEAR, '2010-01-01', '2011-12-31');
SELECT DATEDIFF(YEAR, '2010-12-31', '2011-01-01');

Para responder cómo obtener un domingo:

Si desea un domingo, elija una fecha base que no sea un lunes sino un domingo. Por ejemplo:

DECLARE @dt DATE = '1905-01-01';
SELECT [start_of_week] = DATEADD(WEEK, DATEDIFF(WEEK, @dt, CURRENT_TIMESTAMP), @dt);

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 desea que esas dos respuestas funcionen, entonces debe usar una función que haga depende del DATEFIRST ajuste, por ejemplo,

SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, CURRENT_TIMESTAMP), CURRENT_TIMESTAMP);

Entonces, si cambia su DATEFIRST configurando lunes, martes, lo que sea, el comportamiento cambiará. Según el comportamiento que desee, puede utilizar una de estas funciones:

CREATE FUNCTION dbo.StartOfWeek1 -- always a Sunday
(
    @d DATE
)
RETURNS DATE
AS
BEGIN
    RETURN (SELECT DATEADD(WEEK, DATEDIFF(WEEK, '19050101', @d), '19050101'));
END
GO

...o...

CREATE FUNCTION dbo.StartOfWeek2 -- always the DATEFIRST weekday
(
    @d DATE
)
RETURNS DATE
AS
BEGIN
    RETURN (SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, @d), @d));
END
GO

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 pasé por 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 jueguen 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 "económica":

Function - client processing time / wait time on server replies / total exec time
Gandarez     - 330/2029/2359 - 0:23.6
me datefirst - 329/2123/2452 - 0:24.5
me Sunday    - 357/2158/2515 - 0:25.2
trailmax     - 364/2160/2524 - 0:25.2
Curt         - 424/2202/2626 - 0:26.3

Consulta de asignación "Cara":

Function - client processing time / wait time on server replies / total exec time
Curt         - 1003/134158/135054 - 2:15
Gandarez     -  957/142919/143876 - 2:24
me Sunday    -  932/166817/165885 - 2:47
me datefirst -  939/171698/172637 - 2:53
trailmax     -  958/173174/174132 - 2:54

Puedo transmitir los detalles de mis pruebas si lo desea, deteniéndome aquí ya que esto ya se está volviendo bastante largo. Me sorprendió un poco ver que Curt salió 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 realice algunas pruebas más exhaustivas y publique un blog al respecto... si no tienen ninguna objeción a que publique sus funciones en otro lugar.