2009-08-12 16 views
66

Tengo una consulta que cuenta fechas de la boda de este usuario en la base de datos ...¿Cómo se obtiene la "fecha de inicio de la semana" y la "fecha de fin de semana" del número de semana en SQL Server?

Select 
    Sum(NumberOfBrides) As [Wedding Count], 
    DATEPART(wk, WeddingDate) as [Week Number], 
    DATEPART(year, WeddingDate) as [Year] 
FROM MemberWeddingDates 
Group By DATEPART(year, WeddingDate), DATEPART(wk, WeddingDate) 
Order By Sum(NumberOfBrides) Desc 

¿Cómo se trabaja a cabo cuando el inicio y final de cada semana representado en el conjunto de resultados?

Select 
     Sum(NumberOfBrides) As [Wedding Count], 
     DATEPART(wk, WeddingDate) as [Week Number], 
     DATEPART(year, WeddingDate) as [Year], 
     ??? as WeekStart, 
     ??? as WeekEnd 

    FROM MemberWeddingDates 
    Group By DATEPART(year, WeddingDate), DATEPART(wk, WeddingDate) 
    Order By Sum(NumberOfBrides) Desc 
+1

¡Su pregunta fue suficiente para responder mi pregunta! :) –

Respuesta

115

puede encontrar el día de la semana y hacer una fecha de añadir días para obtener las fechas de inicio y fin ..

DATEADD(dd, -(DATEPART(dw, WeddingDate)-1), WeddingDate) [WeekStart] 

DATEADD(dd, 7-(DATEPART(dw, WeddingDate)), WeddingDate) [WeekEnd] 

Probablemente también quiere mirar a quitarse el momento de la fecha también sin embargo.

+2

Tenga en cuenta que establecer 'DATEFIRST' en cualquier cosa que no sea 7 lo rompe. – Tomalak

+3

No lo "romperá", usará datefirst para establecer WeekStart = a lo que DateFirst dice que es el primer día de una semana.Su versión siempre funcionará los lunes y domingos como inicio y fin de semana, no lo que el servidor está configurado para usar como inicio y fin de semana. –

+0

Hm ... Ese es un punto válido, +1. :) Eliminaré el mío, entonces (aunque para ser un tiro en el pie, fue extremadamente bien dirigido. * G *). – Tomalak

31

Aquí es una solución agnóstica DATEFIRST:

SET DATEFIRST 4  /* or use any other weird value to test it */ 
DECLARE @d DATETIME 

SET @d = GETDATE() 

SELECT 
    @d ThatDate, 
    DATEADD(dd, (@@DATEFIRST + 5 + DATEPART(dw, @d)) % 7, @d) Monday, 
    DATEADD(dd, 6 - (@@DATEFIRST + 5 + DATEPART(dw, @d)) % 7, @d) Sunday 
+9

Esto es genial, pero el lunes no funcionaba para mí. Tuve que agregar "0 -" para obtener los lunes. Mi código del lunes es ahora: DATEADD (dd, 0 - (@ @DATEFIRST + 5 + DATEPART (dw, @d))% 7, @d) – Warren

+0

Subió la respuesta y el comentario de Warrens. La versión 11.0.5058.0 del servidor SQL al menos da la fecha incorrecta para el lunes sin la modificación de Warrens. yo el viernes en su lugar. – Morvael

1

A continuación consulta dará datos entre el inicio y el final de la semana en curso a partir de domingo a sábado

SELECT DOB FROM PROFILE_INFO WHERE DAY(DOB) BETWEEN 
DAY(CURRENT_DATE() - (SELECT DAYOFWEEK(CURRENT_DATE())-1)) 
AND 
DAY((CURRENT_DATE()+(7 - (SELECT DAYOFWEEK(CURRENT_DATE()))))) 
AND 
MONTH(DOB)=MONTH(CURRENT_DATE()) 
0

acabo encontramos con un caso similar con esta, pero la solución aquí parece no ayudarme. Así que trato de resolverlo por mi cuenta. Solo resuelvo la fecha de inicio de la semana, la fecha de finalización de la semana debe ser de lógica similar.

Select 
     Sum(NumberOfBrides) As [Wedding Count], 
     DATEPART(wk, WeddingDate) as [Week Number], 
     DATEPART(year, WeddingDate) as [Year], 
     DATEADD(DAY, 1 - DATEPART(WEEKDAY, dateadd(wk, DATEPART(wk, WeddingDate)-1, DATEADD(yy,DATEPART(year, WeddingDate)-1900,0))), dateadd(wk, DATEPART(wk, WeddingDate)-1, DATEADD(yy,DATEPART(year, WeddingDate)-1900,0))) as [Week Start] 

FROM MemberWeddingDates 
Group By DATEPART(year, WeddingDate), DATEPART(wk, WeddingDate) 
Order By Sum(NumberOfBrides) Desc 
-4

para consultas de Access, puede utilizar el formato de abajo como un campo

"FirstDayofWeek:IIf(IsDate([ForwardedForActionDate]),CDate(Format([ForwardedForActionDate],"dd/mm/yyyy"))-(Weekday([ForwardedForActionDate])-1))" 

cálculo directo permitió ..

11

también puede utilizar esto:

SELECT DATEADD(day, DATEDIFF(day, 0, WeddingDate) /7*7, 0) AS weekstart, 
     DATEADD(day, DATEDIFF(day, 6, WeddingDate-1) /7*7 + 7, 6) AS WeekEnd 
-3

No estoy seguro de lo útil que es esto, pero terminé aquí buscando una solución en Netezza SQL y no pude encontrar uno en el desbordamiento de la pila .

Para Netezza de IBM que usaría algo (por inicio de la semana lun, sol de fin de semana) como:

seleccione next_day (WeddingDate, 'sol') -6 como iniciodesemana,

next_day (WeddingDate, 'SUN') como WeekEnd

2

Aquí hay otra versión. Si su escenario requiere sábado para ser primero días de la semana y el viernes para ser el último día de la Semana, el código de abajo se encargará de que:

DECLARE @myDate DATE = GETDATE() 
    SELECT @myDate, 
    DATENAME(WEEKDAY,@myDate), 
    DATEADD(DD,-(CHOOSE(DATEPART(dw, @myDate), 2,3,4,5,6,7,1)-1),@myDate) AS WeekStartDate, 
    DATEADD(DD,7-CHOOSE(DATEPART(dw, @myDate), 2,3,4,5,6,7,1),@myDate) AS WeekEndDate 

Screenshot of Query

1

Ampliando @Tomalak's respuesta. La fórmula funciona durante días que no sean el domingo y el lunes, pero debe usar valores diferentes para el lugar donde está el 5. Una manera de llegar al valor que se necesita es

Value Needed = 7 - (Value From Date First Documentation for Desired Day Of Week) - 1 

aquí hay un enlace al documento: https://msdn.microsoft.com/en-us/library/ms181598.aspx

Y aquí es una tabla que establece que para usted.

  | DATEFIRST VALUE | Formula Value | 7 - DATEFIRSTVALUE - 1 
Monday | 1    |   5  | 7 - 1- 1 = 5 
Tuesday | 2    |   4  | 7 - 2 - 1 = 4 
Wednesday | 3    |   3  | 7 - 3 - 1 = 3 
Thursday | 4    |   2  | 7 - 4 - 1 = 2 
Friday | 5    |   1  | 7 - 5 - 1 = 1 
Saturday | 6    |   0  | 7 - 6 - 1 = 0 
Sunday | 7    |   -1  | 7 - 7 - 1 = -1 

Pero usted no tiene que recordar que la mesa y sólo la fórmula, y en realidad se puede utilizar un solo ligeramente diferente también la necesidad principal es el uso de un valor que hará que el resto el número correcto de días .

Aquí es un ejemplo de trabajo:

DECLARE @MondayDateFirstValue INT = 1 
DECLARE @FridayDateFirstValue INT = 5 
DECLARE @TestDate DATE = GETDATE() 

SET @MondayDateFirstValue = 7 - @MondayDateFirstValue - 1 
SET @FridayDateFirstValue = 7 - @FridayDateFirstValue - 1 

SET DATEFIRST 6 -- notice this is saturday 

SELECT 
    DATEADD(DAY, 0 - (@@DATEFIRST + @MondayDateFirstValue + DATEPART(dw,@TestDate)) % 7, @TestDate) as MondayStartOfWeek 
    ,DATEADD(DAY, 6 - (@@DATEFIRST + @MondayDateFirstValue + DATEPART(dw,@TestDate)) % 7, @TestDate) as MondayEndOfWeek 
    ,DATEADD(DAY, 0 - (@@DATEFIRST + @FridayDateFirstValue + DATEPART(dw,@TestDate)) % 7, @TestDate) as FridayStartOfWeek 
    ,DATEADD(DAY, 6 - (@@DATEFIRST + @FridayDateFirstValue + DATEPART(dw,@TestDate)) % 7, @TestDate) as FridayEndOfWeek 


SET DATEFIRST 2 --notice this is tuesday 

SELECT 
    DATEADD(DAY, 0 - (@@DATEFIRST + @MondayDateFirstValue + DATEPART(dw,@TestDate)) % 7, @TestDate) as MondayStartOfWeek 
    ,DATEADD(DAY, 6 - (@@DATEFIRST + @MondayDateFirstValue + DATEPART(dw,@TestDate)) % 7, @TestDate) as MondayEndOfWeek 
    ,DATEADD(DAY, 0 - (@@DATEFIRST + @FridayDateFirstValue + DATEPART(dw,@TestDate)) % 7, @TestDate) as FridayStartOfWeek 
    ,DATEADD(DAY, 6 - (@@DATEFIRST + @FridayDateFirstValue + DATEPART(dw,@TestDate)) % 7, @TestDate) as FridayEndOfWeek 

Este método sería agnóstico de la DATEFIRST ajuste que fue lo que necesitaba, ya que estoy construyendo una dimensión de fecha con múltiples métodos de semana incluidos.

0

La respuesta más votada funciona bien excepto la de la 1 semana y la última de de un año. Por ejemplo, si el valor de WeddingDate es '2016-01-01', el resultado será 2015-12-27 y 2016-01-02, pero la respuesta correcta es 2016-01-01 y 2016-01-02.

Prueba esto:

Select 
    Sum(NumberOfBrides) As [Wedding Count], 
    DATEPART(wk, WeddingDate) as [Week Number], 
    DATEPART(year, WeddingDate) as [Year], 
    MAX(CASE WHEN DATEPART(WEEK, WeddingDate) = 1 THEN CAST(DATEADD(YEAR, DATEDIFF(YEAR, 0, WeddingDate), 0) AS date) ELSE DATEADD(DAY, 7 * DATEPART(WEEK, WeddingDate), DATEADD(DAY, -(DATEPART(WEEKDAY, DATEADD(YEAR, DATEDIFF(YEAR, 0, WeddingDate), 0)) + 6), DATEADD(YEAR, DATEDIFF(YEAR, 0, WeddingDate), 0))) END) as WeekStart, 
    MAX(CASE WHEN DATEPART(WEEK, WeddingDate) = DATEPART(WEEK, DATEADD(DAY, -1, DATEADD(YEAR, DATEDIFF(YEAR, 0, WeddingDate) + 1, 0))) THEN DATEADD(DAY, -1, DATEADD(YEAR, DATEDIFF(YEAR, 0, WeddingDate) + 1, 0)) ELSE DATEADD(DAY, 7 * DATEPART(WEEK, WeddingDate) + 6, DATEADD(DAY, -(DATEPART(WEEKDAY, DATEADD(YEAR, DATEDIFF(YEAR, 0, WeddingDate), 0)) + 6), DATEADD(YEAR, DATEDIFF(YEAR, 0, WeddingDate), 0))) END) as WeekEnd 
FROM MemberWeddingDates 
Group By DATEPART(year, WeddingDate), DATEPART(wk, WeddingDate) 
Order By Sum(NumberOfBrides) Desc; 

El resultado será similar a: enter image description here

Funciona para todas las semanas, primero u otros.

1

Rompamos el problema a dos partes:

1) Determinar el día de la semana

Los DATEPART(dw, ...) devuelve un número, 1 ... 7, en relación con DATEFIRST configuración (docs) . La siguiente tabla resume los valores posibles:

            @@DATEFIRST 
+------------------------------------+-----+-----+-----+-----+-----+-----+-----+-----+ 
|         | 1 | 2 | 3 | 4 | 5 | 6 | 7 | DOW | 
+------------------------------------+-----+-----+-----+-----+-----+-----+-----+-----+ 
| DATEPART(dw, /*Mon*/ '20010101') | 1 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 
| DATEPART(dw, /*Tue*/ '20010102') | 2 | 1 | 7 | 6 | 5 | 4 | 3 | 2 | 
| DATEPART(dw, /*Wed*/ '20010103') | 3 | 2 | 1 | 7 | 6 | 5 | 4 | 3 | 
| DATEPART(dw, /*Thu*/ '20010104') | 4 | 3 | 2 | 1 | 7 | 6 | 5 | 4 | 
| DATEPART(dw, /*Fri*/ '20010105') | 5 | 4 | 3 | 2 | 1 | 7 | 6 | 5 | 
| DATEPART(dw, /*Sat*/ '20010106') | 6 | 5 | 4 | 3 | 2 | 1 | 7 | 6 | 
| DATEPART(dw, /*Sun*/ '20010107') | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 7 | 
+------------------------------------+-----+-----+-----+-----+-----+-----+-----+-----+ 

La última columna contiene el valor ideal día de la semana de lunes a domingo semanas *. Con sólo mirar el gráfico nos encontramos con la siguiente ecuación:

(@@DATEFIRST + DATEPART(dw, SomeDate) - 1 - 1) % 7 + 1 

2) Calcular el lunes y el domingo para la fecha dada

Esto es trivial gracias al valor de los días de la semana. Aquí está un ejemplo:

WITH TestData(SomeDate) AS (
    SELECT CAST('20001225' AS DATETIME) UNION ALL 
    SELECT CAST('20001226' AS DATETIME) UNION ALL 
    SELECT CAST('20001227' AS DATETIME) UNION ALL 
    SELECT CAST('20001228' AS DATETIME) UNION ALL 
    SELECT CAST('20001229' AS DATETIME) UNION ALL 
    SELECT CAST('200' AS DATETIME) UNION ALL 
    SELECT CAST('200' AS DATETIME) UNION ALL 
    SELECT CAST('20010101' AS DATETIME) UNION ALL 
    SELECT CAST('20010102' AS DATETIME) UNION ALL 
    SELECT CAST('20010103' AS DATETIME) UNION ALL 
    SELECT CAST('20010104' AS DATETIME) UNION ALL 
    SELECT CAST('20010105' AS DATETIME) UNION ALL 
    SELECT CAST('20010106' AS DATETIME) UNION ALL 
    SELECT CAST('20010107' AS DATETIME) UNION ALL 
    SELECT CAST('20010108' AS DATETIME) UNION ALL 
    SELECT CAST('20010109' AS DATETIME) UNION ALL 
    SELECT CAST('20010110' AS DATETIME) UNION ALL 
    SELECT CAST('20010111' AS DATETIME) UNION ALL 
    SELECT CAST('20010112' AS DATETIME) UNION ALL 
    SELECT CAST('20010113' AS DATETIME) UNION ALL 
    SELECT CAST('20010114' AS DATETIME) 
), TestDataPlusDOW AS (
    SELECT SomeDate, (@@DATEFIRST + DATEPART(dw, SomeDate) - 1 - 1) % 7 + 1 AS DOW 
    FROM TestData 
) 
SELECT 
    FORMAT(SomeDate,       'ddd yyyy-MM-dd') AS SomeDate, 
    FORMAT(DATEADD(dd, -DOW + 1, SomeDate),  'ddd yyyy-MM-dd') AS [Monday], 
    FORMAT(DATEADD(dd, -DOW + 1 + 6, SomeDate), 'ddd yyyy-MM-dd') AS [Sunday] 
FROM TestDataPlusDOW 

Salida:

+------------------+------------------+------------------+ 
| SomeDate  | Monday   | Sunday  | 
+------------------+------------------+------------------+ 
| Mon 2000-12-25 | Mon 2000-12-25 | Sun 2000-12-31 | 
| Tue 2000-12-26 | Mon 2000-12-25 | Sun 2000-12-31 | 
| Wed 2000-12-27 | Mon 2000-12-25 | Sun 2000-12-31 | 
| Thu 2000-12-28 | Mon 2000-12-25 | Sun 2000-12-31 | 
| Fri 2000-12-29 | Mon 2000-12-25 | Sun 2000-12-31 | 
| Sat 2000-12-30 | Mon 2000-12-25 | Sun 2000-12-31 | 
| Sun 2000-12-31 | Mon 2000-12-25 | Sun 2000-12-31 | 
| Mon 2001-01-01 | Mon 2001-01-01 | Sun 2001-01-07 | 
| Tue 2001-01-02 | Mon 2001-01-01 | Sun 2001-01-07 | 
| Wed 2001-01-03 | Mon 2001-01-01 | Sun 2001-01-07 | 
| Thu 2001-01-04 | Mon 2001-01-01 | Sun 2001-01-07 | 
| Fri 2001-01-05 | Mon 2001-01-01 | Sun 2001-01-07 | 
| Sat 2001-01-06 | Mon 2001-01-01 | Sun 2001-01-07 | 
| Sun 2001-01-07 | Mon 2001-01-01 | Sun 2001-01-07 | 
| Mon 2001-01-08 | Mon 2001-01-08 | Sun 2001-01-14 | 
| Tue 2001-01-09 | Mon 2001-01-08 | Sun 2001-01-14 | 
| Wed 2001-01-10 | Mon 2001-01-08 | Sun 2001-01-14 | 
| Thu 2001-01-11 | Mon 2001-01-08 | Sun 2001-01-14 | 
| Fri 2001-01-12 | Mon 2001-01-08 | Sun 2001-01-14 | 
| Sat 2001-01-13 | Mon 2001-01-08 | Sun 2001-01-14 | 
| Sun 2001-01-14 | Mon 2001-01-08 | Sun 2001-01-14 | 
+------------------+------------------+------------------+ 

* Para el domingo a sábado semanas que necesita para ajustar la ecuación sólo un poco, al igual que añadir al menos 1 parte.

Cuestiones relacionadas