2011-09-07 39 views
13

En SQL Server 2008, el isoweek se puede encontrar con esto:Isoweek en SQL Server 2005

SELECT datepart(iso_week, getdate()) 

Antes de SQL Server 2008 no se han incorporado en función de encontrar isoweek.

He estado buscando una buena sintaxis para encontrar un iso_week definido por el usuario para SQL Server 2005. Encontré bastantes soluciones. No me gustó ninguna de las soluciones que encontré, la mayoría de ellas no funcionaron, y fueron demasiado largas.

Como el problema es muy antiguo, esperaría que este problema se agote y se haya encontrado la mejor solución. Sin embargo, no pude encontrar un buen método.

Escribí una solución, que voy a publicar más adelante. Pero antes de hacerlo, quiero estar absolutamente seguro de que nadie más puede igualar la solución que escribí.

Espero ganar la insignia de autoaprendizaje. Insto a las personas a encontrar las mejores respuestas para esta antigua pregunta.

Voy a publicar mi respuesta después de dar a las personas la oportunidad de encontrar una buena solución.

+0

Junto con el número de semana, es importante incluir el año de la semana ISO, ya que puede diferir de la fecha normal del año. Eso parece ser no trivial. –

+0

@MicheldeRuiter enlace a iso_year [aquí] (http://stackoverflow.com/questions/22829604/what-is-iso-year-in-sql-server/22830524#22830524) –

+0

Ya encontré su respuesta, buena para hacer que otros lectores estén al tanto –

Respuesta

12

Aquí hay un enfoque similar al suyo ya que también depende del jueves de esta semana. Pero al final usa la fecha de manera diferente.

  1. Obtenga la fecha de esta (ISO) semana del jueves.

    Su propia solución utiliza la fecha codificada de un jueves conocido. Como alternativa, el jueves de esta semana se podría encontrar con la ayuda de @@DATEFIRST:

    SELECT Th = DATEADD(DAY, 3 - (DATEPART(WEEKDAY, @date) + @@DATEFIRST - 2) % 7, @date) 
    

    (. Yo no estaba luchando demasiado por la fórmula correcta porque era already known para mí)

  2. Obtener el día del Jueves del año:

    SELECT DY = DATEPART(DAYOFYEAR, Th) 
    
  3. utilizar el número para averiguar la semana siguiente manera:

    SELECT ISOWeek = (DY - 1)/7 + 1 
    

Éstos son los cálculos anteriores en una sola instrucción:

SELECT ISOWeek = (DATEPART(DAYOFYEAR, Th) - 1)/7 + 1 
FROM (
    SELECT Th = DATEADD(DAY, 3 - (DATEPART(WEEKDAY, @date) + @@DATEFIRST - 2) % 7, @date) 
) s; 
+0

+1 impresionante, Me tomó un tiempo darme cuenta de lo que estabas haciendo, hasta ahora decidí que estabas haciendo trampa, ¿por qué no pensé en eso? Combiné nuestras respuestas a una solución compacta muy corta. –

+0

Realmente se merece crédito por esta solución, buen compañero de trabajo. –

+0

¡Muchas gracias! –

34

Hay un enlace aquí para otros intentos anteriores http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=60510

Este es el código antiguo para la función

CREATE function f_isoweek(@date datetime) 
RETURNS INT 
as 
BEGIN 
DECLARE @rv int 

SELECT @rv = datediff(ww, dateadd(ww, datediff(d, 0, dateadd(yy, datediff(yy, 0, day4),3))/7,-4),day4) 
FROM (SELECT dateadd(ww, datediff(day, 0, @date)/7, 3) day4) a 

RETURN @rv 
END 

Después de combinar brillante respuesta @AndriyM 's con la mía, estamos abajo a 1 línea. Este es el NUEVO código.

CREATE function f_isoweek(@date datetime) 
RETURNS INT 
as 
BEGIN 

RETURN (datepart(DY, datediff(d, 0, @date)/7 * 7 + 3)+6)/7 
-- replaced code for yet another improvement. 
--RETURN (datepart(DY, dateadd(ww, datediff(d, 0, @date)/7, 3))+6)/7 

END 

explicación para el código antiguo (no va a explicar el nuevo código Es fragmentos de mi código y el código de AndriyM.):

Encontrar día de la semana 4 de la fecha elegida

dateadd(week, datediff(day, 0, @date)/7, 3) 

Hallar isoyear - año de la semana 4 de la semana es siempre el mismo año que el año isoyear de esa semana

datediff(yy, 0, day4) 

Al añadir 3 días para el primer día de la isoyear un día al azar de la primera isoweek del isoyear se encuentra

dateadd(yy, datediff(yy, 0, day4),3) 

encontrar semanas relativa del primer isoweek del isoyear

datediff(d, 0, dateadd(yy, datediff(yy, 0, day4),3))/7 

Encontrar el Lunes menos 4 días de los primeros resultados en isoweek jueves de la semana antes del primer día del primer isoweek del isoyear

dateadd(ww, datediff(d, 0, dateadd(yy, datediff(yy, 0, day4),3))/7,-4) 

Sabiendo primer jueves de t La semana antes del primer isoweek y el primer jueves de la semana elegida, hace que sea bastante fácil calcular la semana, no importa qué fecha de configuración tiene primero, ya que los días de la semana de ambas fechas son los jueves.

datediff(ww, dateadd(ww, datediff(d, 0, dateadd(yy, datediff(yy, 0, day4),3))/7,-4),day4) 
+0

+1. En comparación con esta versión, http://msdn.microsoft.com/en-us/library/ms186755.aspx los tuyos son mucho mejor porque no depende de 'set datefirst 1'. –

+0

¡Agradable! Y me gusta tu '(n + 6)/7' mejor que mi' (n - 1)/7 + 1'. Habría vuelto a votar esto, si pudiera. –

+0

+1000 Reducción de fórmula brillante. –

1

Wow! Muy buen tema y solución para evitar el uso de "set datefirst 1". Solo quiero agregar algo. Si, como yo, también desea devolver el año con la semana ISO, como "2015-01" como "Año 2015, Semana 01", podría ser útil para la elaboración de informes. ¡Dado que el año de la semana ISO puede ser diferente del año real de la fecha! Así es como lo hice en combinación con tu código.

DECLARE @Date AS DATETIME 
SET @Date = '2014-12-31' 
SELECT 
     CAST(CASE WHEN MONTH(@Date) = 1 AND Q.ISOweek > 50 THEN YEAR(@Date) - 1 
       WHEN MONTH(@Date) = 12 AND Q.ISOweek < 3 THEN YEAR(@Date) + 1 
       ELSE YEAR(@Date) 
      END 
      AS VARCHAR(4)) 
    + '-' 
    + RIGHT('00' + CAST(Q.ISOweek AS NVARCHAR(2)), 2) AS ISOweek 
FROM (SELECT (datepart(DY, datediff(d, 0, @Date)/7 * 7 + 3) + 6)/7 AS ISOweek) Q 

volveremos "2015-01".

+1

Ya escribí un script simple para iso_year. http://stackoverflow.com/questions/22829604/what-is-iso-year-in-sql-server/22830524#22830524 –

0

Necesitaba algo similar para PowerQuery & PowerBI y, en base a la respuesta de t-clausen.dk, pude hacer esta ecuación. Funciona igual que el suyo pero usa la sintaxis de PowerQuery. También la fecha base para el DATEDIFF de 0 1/1/1900 estaba en SQL pero en PowerQuery es 12/30/1899, así que uso 2 en lugar del 0.

ISO Week = Number.RoundDown((Date.DayOfYear(Date.From(Duration.Days(([Date]-Date.From(2))/7)*7+5))+6)/7) 

También necesitaba el Año de modo ISO hice un ajuste en el cálculo de la Semana de la ISO y ocurrió:

ISO Year = Date.Year(Date.From(Duration.Days(([Date]-Date.From(2))/7)*7+3)) 

Cambiar el [Date] hacer referencia a la columna de fecha en los datos.

Cuestiones relacionadas