Meses entre dos dates

¿Es posible get month names entre dos dates en SQl

es decir, 2011-05-01 Y 2011-08-01 son las inputs que solo quiero que el resultado sea

 ------------ Month ------------ May June July August 

Si algún cuerpo conoce la consulta, por favor comparte.

 DECLARE @StartDate DATETIME, @EndDate DATETIME; SELECT @StartDate = '20110501' ,@EndDate = '20110801'; SELECT DATENAME(MONTH, DATEADD(MONTH, x.number, @StartDate)) AS MonthName FROM master.dbo.spt_values x WHERE x.type = 'P' AND x.number <= DATEDIFF(MONTH, @StartDate, @EndDate); 

Resultados:

 MonthName ------------------------------ May June July August (4 row(s) affected) 

Puede hacer esto con un CTE recursivo, creando una tabla de dates y obteniendo el nombre del mes de cada una:

 declare @start DATE = '2011-05-01' declare @end DATE = '2011-08-01' ;with months (date) AS ( SELECT @start UNION ALL SELECT DATEADD(month,1,date) from months where DATEADD(month,1,date)<=@end ) select Datename(month,date) from months 

También modifiqué la respuesta de Jamiec para publicar el último día del mes.

 declare @start DATE = '2014-05-01' declare @end DATE = getdate() ;with months (date) AS ( SELECT @start UNION ALL SELECT DATEADD(month,1,date) from months where DATEADD(month,1,date) < @end ) select [MonthName] = DATENAME(mm ,Date) ,[MonthNumber] = DATEPART(mm ,Date) ,[LastDayOfMonth] = DATEPART(dd,EOMONTH(Date)) ,[MonthYear] = DATEPART(yy ,Date) from months 

Que da salida:

 MonthName MonthNumber LastDayOfMonth MonthYear May 5 31 2014 June 6 30 2014 July 7 31 2014 August 8 31 2014 September 9 30 2014 

Inspirado por la respuesta de Jamiec , pero solucionando el problema con el day más grande que el day :

 declare @start DATE declare @end DATE SELECT @start='2011-05-19' , @end='2011-08-15' ;with months (date) AS ( SELECT DATEADD(DAY,1,EOMONTH(@start,-1)) UNION ALL SELECT DATEADD(month,1,date) from months where DATEADD(month,1,date) < EOMONTH(@end) ) select Datename(month,date) from months 
  declare @start DATE = '2011-05-30' declare @end DATE = '2011-06-10' ;with months (date) AS ( SELECT @start UNION ALL SELECT DATEADD(month,1,date) from months where DATEADD(month,1,date)<= DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,@end)+1,0)) ) select Datename(month,date) from months 

Si tiene una tabla MonthNames contiene nombres de cada mes, puede ejecutar

 SELECT MonthName FROM MonthNames WHERE MonthNumber BETWEEN Month(&date1) AND Month(&date2); 

Table MonthNames será como

MonthName, MonthNumber
Enero 1
Febrero 2
3 de marzo

y así…

Bueno, @bogdhan sahlean ha dado una buena solución basada en sets, pero restringe los valores hasta 2048 teniendo en count la date tipo de datos y date y datetime2 que el range para el año es 0001-01-01 a 9999-12-31 , de MSDN

Rango de dates 0001-01-01 a 9999-12-31

Enero 1,1 CE hasta el 31 de diciembre de 9999 CE

a pesar de que este es el caso extremo, pero vale la pena saberlo. ¿Qué pasa si un día alguien está tratando de proyectar meses más de 170 años 🙂

Incluso las respuestas más votadas no están cumpliendo algunos casos extremos (cuando la date de inicio> la date de finalización no muestra el mes de la date de finalización, también, la consulta recursiva falla después de 100 ejecuciones por defecto). Y también usando cte recursivo para la iteración que es de alto performance cuando se usa masivamente.

Ahora, una solución mejor (en mi humilde opinión) es usar una tabla de calendar o una tabla de conteo para generar los meses entre dos dates. Si no se puede crear una tabla, hay una mejor alternativa para usar Itzik ben Gans en cascada CTE para generar tabla de numbers. ( Aquí ) Que es más rápido, Sin lecturas lógicas, físicas, Sin table de trabajo NADA

Aquí está el código

 DECLARE @start DATETIME2 = '00010101' DECLARE @end DATETIME2 = '99991231' ;WITH lv0 AS (SELECT 0 g UNION ALL SELECT 0) ,lv1 AS (SELECT 0 g FROM lv0 a CROSS JOIN lv0 b) -- 4 ,lv2 AS (SELECT 0 g FROM lv1 a CROSS JOIN lv1 b) -- 16 ,lv3 AS (SELECT 0 g FROM lv2 a CROSS JOIN lv2 b) -- 256 ,lv4 AS (SELECT 0 g FROM lv3 a CROSS JOIN lv3 b) -- 65,536 ,lv5 AS (SELECT 0 g FROM lv4 a CROSS JOIN lv4 b) -- 4,294,967,296 ,Tally (n) AS (SELECT 0 UNION SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM lv5) SELECT DATENAME(YEAR,DATEADD(MONTH,N,@start)) AS [Year Part], DATENAME(MONTH,DATEADD(MONTH,n,@start)) AS [Month Part] FROM Tally where N between 0 and DATEDIFF(mm,@start,@end) ORDER BY n; 

NB: He agregado SELECT 0 para comenzar los numbers desde la 0ª position

El performance que se muestra en mi PC es

Método Itzik

(119988 fila (s) afectadas)

Tiempos de ejecución de SQL Server: time de CPU = 187 ms, time transcurrido = 706 ms. Análisis SQL Server y time de compilation: time de CPU = 0 ms, time transcurrido = 0 ms.

Una de las soluciones recursivas dadas aquí que toma un time de

(119988 fila (s) afectadas) Tabla 'Tabla de trabajo'. Número de escaneo 2, lecturas lógicas 719923, lecturas físicas 0, lecturas de lectura anticipada 0, lecturas lógicas de lob 0, lecturas físicas de lob 0, lecturas de lectura anticipada de lob 0.

Tiempos de ejecución de SQL Server: time de CPU = 890 ms, time transcurrido = 1069 ms.

El performance entre la tabla de recuento, la tabla de calendar y la tabla de numbers de itzik puede variar ligeramente, pero funciona como un amuleto con todos los ranges de dates que proporcione.

Prueba esto:

 declare @sd date=getdate(), @ld date='2016-01-01' select Datename(month,dateadd(month,number,GETDATE())), number from master.dbo.spt_values where type='p' and dateadd(month,number,GETDATE()) <= @ld