How to populate a table with a range of dates?

后端 未结 10 1263
夕颜
夕颜 2020-11-22 04:24

I need a MySQL table to hold ALL DATES between 2011-01-01 and 2011-12-31. I have created a table with one column names \"_date\", type DATE.

With what query can I po

相关标签:
10条回答
  • 2020-11-22 04:58

    if you're in a situation like me where procedures are prohibited, and your sql user does not have permissions for insert, therefore insert not allowed, but you want to generate a list of dates in a specific period, say current year to do some aggregation, use this

    select * from 
    (select affffdate('1970-01-01',t4*10000 + t3*1000 + t2*100 + t1*10 + t0) gen_date from
     (select 0 t0 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t0,
     (select 0 t1 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t1,
     (select 0 t2 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t2,
     (select 0 t3 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t3,
     (select 0 t4 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t4) v
    where gen_date between '2017-01-01' and '2017-12-31'
    
    0 讨论(0)
  • 2020-11-22 05:01

    Try this:

    DROP PROCEDURE IF EXISTS filldates;
    DELIMITER |
    CREATE PROCEDURE filldates(dateStart DATE, dateEnd DATE)
    BEGIN
      WHILE dateStart <= dateEnd DO
        INSERT INTO tablename (_date) VALUES (dateStart);
        SET dateStart = date_add(dateStart, INTERVAL 1 DAY);
      END WHILE;
    END;
    |
    DELIMITER ;
    CALL filldates('2011-01-01','2011-12-31');
    

    Here's the SQL Fiddle to play with it: http://sqlfiddle.com/#!2/65d13/1

    EDIT (to check if date already exists) as asked by Andrew Fox.

    CREATE PROCEDURE filldates(dateStart DATE, dateEnd DATE)
    
    BEGIN
    
    DECLARE adate date;
    
        WHILE dateStart <= dateEnd DO
    
            SET adate = (SELECT mydate FROM MyDates WHERE mydate = dateStart);
    
            IF adate IS NULL THEN BEGIN
    
                INSERT INTO MyDates (mydate) VALUES (dateStart);
    
            END; END IF;
    
            SET dateStart = date_add(dateStart, INTERVAL 1 DAY);
    
        END WHILE;
    
    END;//
    

    Here's the SQL Fiddle to play with it: http://sqlfiddle.com/#!2/66f86/1

    0 讨论(0)
  • 2020-11-22 05:08

    I found this paste-and-go variant working:

    DROP PROCEDURE IF EXISTS FillCalendar;
    DROP TABLE IF EXISTS calendar;
    CREATE TABLE IF NOT EXISTS calendar(calendar_date DATE NOT NULL PRIMARY KEY);
    
    DELIMITER $$
        CREATE PROCEDURE FillCalendar(start_date DATE, end_date DATE)
        BEGIN
        DECLARE crt_date DATE;
        SET crt_date = start_date;
        WHILE crt_date <= end_date DO
            INSERT IGNORE INTO calendar VALUES(crt_date);
            SET crt_date = ADDDATE(crt_date, INTERVAL 1 DAY);
        END WHILE;
        END$$
    DELIMITER ;
    
    CALL FillCalendar('2013-01-01', '2013-01-03');
    CALL FillCalendar('2013-01-01', '2013-01-07');
    
    0 讨论(0)
  • 2020-11-22 05:09

    Thanks to IvanD. I've got a better solution which allowes you to create a specified calendar table. For example, if I'm trying to create a table of 2014-04, it looks like this:

    SELECT (CURDATE() - INTERVAL c.number DAY) AS DATE
    FROM 
    (
        SELECT singles + tens + hundreds number FROM 
        ( 
            SELECT 0 singles
            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
        ) singles JOIN 
        (
            SELECT 0 tens
            UNION ALL SELECT  10 UNION ALL SELECT  20 UNION ALL SELECT  30
            UNION ALL SELECT  40 UNION ALL SELECT  50 UNION ALL SELECT  60
            UNION ALL SELECT  70 UNION ALL SELECT  80 UNION ALL SELECT  90
        ) tens  JOIN 
        (
            SELECT 0 hundreds
            UNION ALL SELECT  100 UNION ALL SELECT  200 UNION ALL SELECT  300
            UNION ALL SELECT  400 UNION ALL SELECT  500 UNION ALL SELECT  600
            UNION ALL SELECT  700 UNION ALL SELECT  800 UNION ALL SELECT  900
        ) hundreds
        ORDER BY number DESC
    ) c  
    WHERE c.number BETWEEN 
    DAYOFYEAR(NOW()) - DAYOFYEAR('2014-04-01')-  DAY(LAST_DAY('2014-04-01')) +1
    AND 
    DAYOFYEAR(NOW()) - DAYOFYEAR('2014-04-01')
    
    0 讨论(0)
  • 2020-11-22 05:17

    If you have a table with a large enough contiguous set of ids you could use -

    INSERT INTO tablename (_date)
    SELECT '2011-01-01' + INTERVAL (id - 1) DAY
    FROM some_table_with_lots_of_ids
    WHERE id BETWEEN 1 AND 365
    

    note: but be aware that this might get you in trouble during leap-years (having 366 days)

    0 讨论(0)
  • 2020-11-22 05:18

    I recently had a need to create a calendar_date table as below:

    CREATE TABLE `calendar_date` (
        `date`    DATE NOT NULL      -- A calendar date.
        , `day`   SMALLINT NOT NULL  -- The day of the year for the date, 1-366.
        , `month` TINYINT NOT NULL   -- The month number, 1-12.
        , `year`  SMALLINT NOT NULL  -- The year.
        , PRIMARY KEY (`id`));
    

    I then populated it with all possible dates between January 1, 2001 and December 31, 2100 (both inclusive) using the query below:

    INSERT INTO `calendar_date` (`date`
        , `day`
        , `month`
        , `year`)
    SELECT
        DATE
        , INCREMENT + 1
        , MONTH(DATE)
        , YEAR(DATE)
    FROM
        -- Generate all possible dates for every year from 2001 to 2100.
        (SELECT
            DATE_ADD(CONCAT(YEAR, '-01-01'), INTERVAL INCREMENT DAY) DATE
            , INCREMENT
        FROM
            (SELECT
                (UNITS + TENS + HUNDREDS) INCREMENT
            FROM
                (SELECT 0 UNITS UNION
                SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION
                SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION
                SELECT 7 UNION SELECT 8 UNION SELECT 9) UNITS
            CROSS JOIN
                (SELECT 0 TENS UNION
                SELECT 10 UNION SELECT 20 UNION SELECT 30 UNION
                SELECT 40 UNION SELECT 50 UNION SELECT 60 UNION
                SELECT 70 UNION SELECT 80 UNION SELECT 90) TENS
            CROSS JOIN
                (SELECT 0 HUNDREDS UNION
                SELECT 100 UNION SELECT 200 UNION SELECT 300 UNION
                SELECT 400 UNION SELECT 500 UNION SELECT 600 UNION
                SELECT 700 UNION SELECT 800 UNION SELECT 900) HUNDREDS
            ) INCREMENT
            -- For every year from 2001 to 2100, find the number of days in the year.
            , (SELECT
                YEAR
                , DAYOFYEAR(CONCAT(YEAR, '-12-31')) - DAYOFYEAR(CONCAT(YEAR, '-01-01')) + 1 DAYS
            FROM
                -- Generate years from 2001 to 2100.
                (SELECT
                    (2000 + UNITS + TENS) YEAR
                FROM
                    (SELECT 0 UNITS UNION
                    SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION
                    SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION
                    SELECT 7 UNION SELECT 8 UNION SELECT 9) UNITS
                CROSS JOIN
                    (SELECT 0 TENS UNION
                    SELECT 10 UNION SELECT 20 UNION SELECT 30 UNION
                    SELECT 40 UNION SELECT 50 UNION SELECT 60 UNION
                    SELECT 70 UNION SELECT 80 UNION SELECT 90) TENS
                ) YEAR
            WHERE
                YEAR BETWEEN 2001 AND 2100
            ) YEAR
          WHERE
              INCREMENT BETWEEN 0 AND DAYS - 1
          ORDER BY
              YEAR
              , INCREMENT) DATE;
    

    On my local MySQL database, the INSERT query took just a few seconds. Hope this helps someone.

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