generar días a partir del rango de fechas

Resuelto Pentium10 asked hace 14 años • 30 respuestas

Me gustaría ejecutar una consulta como

select ... as days where `date` is between '2010-01-20' and '2010-01-24'

Y devolver datos como:

días
----------
2010-01-20
2010-01-21
2010-01-22
2010-01-23
2010-01-24
Pentium10 avatar Jan 29 '10 02:01 Pentium10
Aceptado

Esta solución no utiliza bucles, procedimientos ni tablas temporales . La subconsulta genera fechas de los últimos 10.000 días y podría extenderse para retroceder o avanzar tanto como desee.

select a.Date 
from (
    select curdate() - INTERVAL (a.a + (10 * b.a) + (100 * c.a) + (1000 * d.a) ) DAY as Date
    from (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as a
    cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as b
    cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as c
    cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as d
) a
where a.Date between '2010-01-20' and '2010-01-24' 

Producción:

Date
----------
2010-01-24
2010-01-23
2010-01-22
2010-01-21
2010-01-20

Notas sobre el rendimiento

Probándolo aquí , el rendimiento es sorprendentemente bueno: la consulta anterior tarda 0,0009 segundos.

Si ampliamos la subconsulta para generar aprox. 100.000 números (y, por lo tanto, aproximadamente 274 años de fechas), se ejecuta en 0,0458 segundos.

Por cierto, esta es una técnica muy portátil que funciona con la mayoría de las bases de datos con pequeños ajustes.

Ejemplo de SQL Fiddle que devuelve 1000 días

D'Arcy Rittich avatar Jan 28 '2010 20:01 D'Arcy Rittich

Aquí hay otra variación que usa vistas:

CREATE VIEW digits AS
  SELECT 0 AS digit UNION ALL
  SELECT 1 UNION ALL
  SELECT 2 UNION ALL
  SELECT 3 UNION ALL
  SELECT 4 UNION ALL
  SELECT 5 UNION ALL
  SELECT 6 UNION ALL
  SELECT 7 UNION ALL
  SELECT 8 UNION ALL
  SELECT 9;

CREATE VIEW numbers AS
  SELECT
    ones.digit + tens.digit * 10 + hundreds.digit * 100 + thousands.digit * 1000 AS number
  FROM
    digits as ones,
    digits as tens,
    digits as hundreds,
    digits as thousands;

CREATE VIEW dates AS
  SELECT
    SUBDATE(CURRENT_DATE(), number) AS date
  FROM
    numbers;

Y luego puedes simplemente hacer (¿ves lo elegante que es?):

SELECT
  date
FROM
  dates
WHERE
  date BETWEEN '2010-01-20' AND '2010-01-24'
ORDER BY
  date

Actualizar

Vale la pena señalar que solo podrás generar fechas pasadas a partir de la fecha actual . Si desea generar cualquier tipo de rango de fechas (pasado, futuro y intermedio), deberá utilizar esta vista en su lugar:

CREATE VIEW dates AS
  SELECT
    SUBDATE(CURRENT_DATE(), number) AS date
  FROM
    numbers
  UNION ALL
  SELECT
    ADDDATE(CURRENT_DATE(), number + 1) AS date
  FROM
    numbers;
Stéphane avatar Jun 21 '2012 16:06 Stéphane

La respuesta aceptada no funcionó para PostgreSQL (error de sintaxis en "a" o cerca de ella).

La forma de hacer esto en PostgreSQL es mediante el uso generate_seriesde funciones, es decir:

SELECT day::date
FROM generate_series('2010-01-20', '2010-01-24', INTERVAL '1 day') day;

    day
------------
 2010-01-20
 2010-01-21
 2010-01-22
 2010-01-23
 2010-01-24
(5 rows)
Dmitry Gusev avatar Jul 05 '2015 11:07 Dmitry Gusev

Usando una expresión de tabla común (CTE) recursiva, puede generar una lista de fechas y luego seleccionarla. Obviamente, normalmente no querrías crear tres millones de fechas, así que esto sólo ilustra las posibilidades. Simplemente podría limitar el rango de fechas dentro del CTE y omitir la cláusula dónde de la declaración de selección usando el CTE.

with [dates] as (
    select convert(datetime, '1753-01-01') as [date] --start
    union all
    select dateadd(day, 1, [date])
    from [dates]
    where [date] < '9999-12-31' --end
)
select [date]
from [dates]
where [date] between '2013-01-01' and '2013-12-31'
option (maxrecursion 0)

En Microsoft SQL Server 2005, generar la lista CTE de todas las fechas posibles tomó 1:08. Generar cien años tomó menos de un segundo.

Joshua avatar Aug 14 '2013 00:08 Joshua

Consulta MSSQL

select datetable.Date 
from (
    select DATEADD(day,-(a.a + (10 * b.a) + (100 * c.a)),getdate()) AS Date
    from (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4
     union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as a

    cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4
     union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as b

    cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4
     union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as c
) datetable
where datetable.Date between '2014-01-20' and '2014-01-24' 
order by datetable.Date DESC

Producción

Date
-----
2014-01-23 12:35:25.250
2014-01-22 12:35:25.250
2014-01-21 12:35:25.250
2014-01-20 12:35:25.250
SUHAIL AG avatar Sep 28 '2014 08:09 SUHAIL AG