generar días a partir del rango de fechas
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
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
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;
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_series
de 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)
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.
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