Obtenga una lista de fechas entre dos fechas usando una función

Resuelto Dan Atkinson asked hace 15 años • 21 respuestas

Mi pregunta es similar a esta pregunta de MySQL, pero destinada a SQL Server:

¿Existe alguna función o consulta que devuelva una lista de días entre dos fechas? Por ejemplo, digamos que hay una función llamada ExplodeDates:

SELECT ExplodeDates('2010-01-01', '2010-01-13');

Esto devolvería una tabla de una sola columna con los valores:

2010-01-01
2010-01-02
2010-01-03
2010-01-04
2010-01-05
2010-01-06
2010-01-07
2010-01-08
2010-01-09
2010-01-10
2010-01-11
2010-01-12
2010-01-13

Estoy pensando que una tabla de calendario/números podría ayudarme aquí.


Actualizar

Decidí echar un vistazo a las tres respuestas de código proporcionadas y los resultados de la ejecución, como porcentaje del lote total, son:

  • Respuesta de Rob Farley : 18%
  • Respuesta de StingyJack : 41%
  • La respuesta de KM : 41%

Más bajo es mejor

Acepté la respuesta de Rob Farley, ya que era la más rápida, aunque las soluciones de tablas de números (utilizadas tanto por KM como por StingyJack en sus respuestas) son una de mis favoritas. El de Rob Farley fue dos tercios más rápido.

Actualización 2

La respuesta de Alivia es mucho más concisa. He cambiado la respuesta aceptada.

Dan Atkinson avatar Sep 04 '09 18:09 Dan Atkinson
Aceptado

Estas pocas líneas son la respuesta simple a esta pregunta en el servidor SQL.

WITH mycte AS
(
  SELECT CAST('2011-01-01' AS DATETIME) DateValue
  UNION ALL
  SELECT  DateValue + 1
  FROM    mycte   
  WHERE   DateValue + 1 < '2021-12-31'
)

SELECT  DateValue
FROM    mycte
OPTION (MAXRECURSION 0)
Alivia avatar Feb 09 '2012 09:02 Alivia

Pruebe algo como esto:

CREATE FUNCTION dbo.ExplodeDates(@startdate datetime, @enddate datetime)
returns table as
return (
with 
 N0 as (SELECT 1 as n UNION ALL SELECT 1)
,N1 as (SELECT 1 as n FROM N0 t1, N0 t2)
,N2 as (SELECT 1 as n FROM N1 t1, N1 t2)
,N3 as (SELECT 1 as n FROM N2 t1, N2 t2)
,N4 as (SELECT 1 as n FROM N3 t1, N3 t2)
,N5 as (SELECT 1 as n FROM N4 t1, N4 t2)
,N6 as (SELECT 1 as n FROM N5 t1, N5 t2)
,nums as (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 1)) as num FROM N6)
SELECT DATEADD(day,num-1,@startdate) as thedate
FROM nums
WHERE num <= DATEDIFF(day,@startdate,@enddate) + 1
);

Luego usas:

SELECT *
FROM dbo.ExplodeDates('20090401','20090531') as d;

Editado (después de la aceptación):

Tenga en cuenta... si ya tiene una tabla de números lo suficientemente grande, entonces debería usar:

CREATE FUNCTION dbo.ExplodeDates(@startdate datetime, @enddate datetime)
returns table as
return (
SELECT DATEADD(day,num-1,@startdate) as thedate
FROM nums
WHERE num <= DATEDIFF(day,@startdate,@enddate) + 1
);

Y puedes crear una tabla de este tipo usando:

CREATE TABLE dbo.nums (num int PRIMARY KEY);
INSERT dbo.nums values (1);
GO
INSERT dbo.nums SELECT num + (SELECT COUNT(*) FROM nums) FROM nums
GO 20

Estas líneas crearán una tabla de números que contiene 1 millón de filas... y mucho más rápido que insertarlas una por una.

NO debe crear su función ExplodeDates usando una función que implique COMENZAR y FINALIZAR, ya que el Optimizador de consultas no puede simplificar la consulta en absoluto.

Rob Farley avatar Sep 04 '2009 11:09 Rob Farley