find missing dates from date range

后端 未结 6 2022
小蘑菇
小蘑菇 2020-12-16 05:49

I have query regarding get the dates which are not exists in database table.

I have below dates in database.

2013-08-02
2013-08-02
2013-08-02
2013-08         


        
6条回答
  •  执笔经年
    2020-12-16 06:21

    My bet would be probably to create a dedicated Calendar table just to be able to use it on a LEFT JOIN.

    You could create the table on per need basis, but as it will not represent a such large amount of data, the simplest and probably most efficient approach is to create it once for all, as I do below using a stored procedure:

    --
    -- Create a dedicated "Calendar" table
    --
    CREATE TABLE Calendar (day DATE PRIMARY KEY);
    
    DELIMITER //
    CREATE PROCEDURE init_calendar(IN pStart DATE, IN pEnd DATE)
    BEGIN
        SET @theDate := pStart;
        REPEAT
            -- Here I use *IGNORE* in order to be able
            -- to call init_calendar again for extend the
            -- "calendar range" without to bother with
            -- "overlapping" dates
            INSERT IGNORE INTO Calendar VALUES (@theDate);
            SET @theDate := @theDate + INTERVAL 1 DAY;
        UNTIL @theDate > pEnd END REPEAT;
    END; //
    DELIMITER ;
    
    CALL init_calendar('2010-01-01','2015-12-31');
    

    In this example, the Calendar hold 2191 consecutive days, which represent at a roughly estimate less that 15KB. And storing all the dates from the 21th century will represent less that 300KB...

    Now, this is your actual data table as described in the question:

    --
    -- *Your* actual data table
    --
    CREATE TABLE tbl (theDate DATE);
    INSERT INTO tbl VALUES 
        ('2013-08-02'),
        ('2013-08-02'),
        ('2013-08-02'),
        ('2013-08-03'),
        ('2013-08-05'),
        ('2013-08-08'),
        ('2013-08-08'),
        ('2013-08-09'),
        ('2013-08-10'),
        ('2013-08-13'),
        ('2013-08-13'),
        ('2013-08-13');
    

    And finally the query:

    --
    -- Now the query to find date not "in range"
    --
    
    SET @start = '2013-08-01';
    SET @end = '2013-08-13';
    
    SELECT Calendar.day FROM Calendar LEFT JOIN tbl
        ON Calendar.day = tbl.theDate
        WHERE Calendar.day BETWEEN @start AND @end
        AND tbl.theDate IS NULL;
    

    Producing:

    +------------+
    | day        |
    +------------+
    | 2013-08-01 |
    | 2013-08-04 |
    | 2013-08-06 |
    | 2013-08-07 |
    | 2013-08-11 |
    | 2013-08-12 |
    +------------+
    

提交回复
热议问题