Esta solução não usa sem loops, procedimentos ou tabelas temporárias . A subconsulta gera datas para os últimos 10.000 dias e pode ser estendida para retroceder ou avançar conforme desejar.
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'
Saída:
Date
----------
2010-01-24
2010-01-23
2010-01-22
2010-01-21
2010-01-20
Observações sobre desempenho
Testando aqui , o desempenho é surpreendentemente bom:a consulta acima leva 0,0009 segundos.
Se estendermos a subconsulta para gerar aprox. 100.000 números (e, portanto, cerca de 274 anos de datas), ele é executado em 0,0458 seg.
Aliás, esta é uma técnica muito portátil que funciona com a maioria dos bancos de dados com pequenos ajustes.
Exemplo do SQL Fiddle retornando 1.000 dias