generate days from date range

后端 未结 29 2477
渐次进展
渐次进展 2020-11-21 05:19

I would like to run a query like

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

And return data like:

相关标签:
29条回答
  • 2020-11-21 06:01
    DELIMITER $$
    CREATE PROCEDURE GenerateRangeDates(IN dateStart DATE, IN dateEnd DATE)
    BEGIN
    
        CREATE TEMPORARY TABLE IF NOT EXISTS dates (day DATE);
    
        loopDate: LOOP
            INSERT INTO dates(day) VALUES (dateStart); 
            SET dateStart = DATE_ADD(dateStart, INTERVAL 1 DAY);
    
            IF dateStart <= dateEnd 
                THEN ITERATE loopDate;
                ELSE LEAVE loopDate;
            END IF;
        END LOOP loopDate;
    
        SELECT day FROM dates;
        DROP TEMPORARY TABLE IF EXISTS dates;
    
    END 
    $$
    
    -- Call procedure
    call GenerateRangeDates( 
            now() - INTERVAL 40 DAY,
            now()
        );
    
    0 讨论(0)
  • 2020-11-21 06:02

    Can create a procedure also to create calendar table with timestmap different from day. If you want a table for each quarter

    e.g.

    2019-01-22 08:45:00
    2019-01-22 09:00:00
    2019-01-22 09:15:00
    2019-01-22 09:30:00
    2019-01-22 09:45:00
    2019-01-22 10:00:00
    

    you can use

    CREATE DEFINER=`root`@`localhost` PROCEDURE `generate_calendar_table`()
    BEGIN
    
    select unix_timestamp('2014-01-01 00:00:00') into @startts;
    select unix_timestamp('2025-01-01 00:00:00') into @endts;
    
    if ( @startts < @endts ) then
    
        DROP TEMPORARY TABLE IF EXISTS calendar_table_tmp;
    
        CREATE TEMPORARY TABLE calendar_table_tmp (ts int, dt datetime); 
    
        WHILE ( @startts < @endts)
            DO 
            SET @startts = @startts + 900;
            INSERT calendar_table_tmp VALUES (@startts, from_unixtime(@startts));
        END WHILE;
    
    END if;
    
    END
    
    
    

    and then manipulate through

    select ts, dt from calendar_table_tmp;
    
    

    that give you also ts

    '1548143100', '2019-01-22 08:45:00'
    '1548144000', '2019-01-22 09:00:00'
    '1548144900', '2019-01-22 09:15:00'
    '1548145800', '2019-01-22 09:30:00'
    '1548146700', '2019-01-22 09:45:00'
    '1548147600', '2019-01-22 10:00:00'
    

    from here you can start to add other information such as

    select ts, dt, weekday(dt) as wd from calendar_table_tmp;
    
    

    or create a real table with create table statement

    0 讨论(0)
  • 2020-11-21 06:03

    Shorter than accepted answer, same idea:

    (SELECT TRIM('2016-01-05' + INTERVAL a + b DAY) date
    FROM
    (SELECT 0 a UNION SELECT 1 a UNION SELECT 2 UNION SELECT 3
    UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7
    UNION SELECT 8 UNION SELECT 9 ) d,
    (SELECT 0 b UNION SELECT 10 UNION SELECT 20
    UNION SELECT 30 UNION SELECT 40) m
    WHERE '2016-01-05' + INTERVAL a + b DAY  <=  '2016-01-21')
    
    0 讨论(0)
  • 2020-11-21 06:03

    For anyone who wants this as a saved view (MySQL doesn't support nested select statements in views):

    create view zero_to_nine as
        select 0 as n 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 date_range as
        select curdate() - INTERVAL (a.n + (10 * b.n) + (100 * c.n)) DAY as date
        from zero_to_nine as a
        cross join zero_to_nine as b
        cross join zero_to_nine as c;
    

    You can then do

    select * from date_range
    

    to get

    date
    ---
    2017-06-06
    2017-06-05
    2017-06-04
    2017-06-03
    2017-06-02
    ...
    
    0 讨论(0)
  • 2020-11-21 06:04
    set language  'SPANISH'
    DECLARE @table table(fechaDesde datetime , fechaHasta datetime ) 
    INSERT @table VALUES('20151231' , '20161231');
    WITH x AS 
        (
            SELECT   DATEADD( m , 1 ,fechaDesde ) as fecha  FROM @table
            UNION ALL
            SELECT  DATEADD( m , 1 ,fecha )
            FROM @table t INNER JOIN x ON  DATEADD( m , 1 ,x.fecha ) <= t.fechaHasta
        )
    SELECT LEFT( CONVERT( VARCHAR, fecha , 112 ) , 6 ) as Periodo_Id 
    ,DATEPART ( dd, DATEADD(dd,-(DAY(fecha)-1),fecha)) Num_Dia_Inicio
    ,DATEADD(dd,-(DAY(fecha)-1),fecha) Fecha_Inicio
    ,DATEPART ( mm , fecha ) Mes_Id
    ,DATEPART ( yy , fecha ) Anio
    ,DATEPART ( dd, DATEADD(dd,-(DAY(DATEADD(mm,1,fecha))),DATEADD(mm,1,fecha))) Num_Dia_Fin
    ,DATEADD(dd,-(DAY(DATEADD(mm,1,fecha))),DATEADD(mm,1,fecha)) ultimoDia
    ,datename(MONTH, fecha) mes
    ,'Q' + convert(varchar(10),  DATEPART(QUARTER, fecha)) Trimestre_Name
    FROM x 
    OPTION(MAXRECURSION 0)
    
    0 讨论(0)
  • 2020-11-21 06:05

    This solution uses no loops, procedures, or temp tables. The subquery generates dates for the last 10,000 days, and could be extended to go as far back or forward as you wish.

    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' 
    

    Output:

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

    Notes on Performance

    Testing it out here, the performance is surprisingly good: the above query takes 0.0009 sec.

    If we extend the subquery to generate approx. 100,000 numbers (and thus about 274 years worth of dates), it runs in 0.0458 sec.

    Incidentally, this is a very portable technique that works with most databases with minor adjustments.

    SQL Fiddle example returning 1,000 days

    0 讨论(0)
提交回复
热议问题