Get a list of dates between two dates

后端 未结 20 2123
醉梦人生
醉梦人生 2020-11-22 00:26

Using standard mysql functions is there a way to write a query that will return a list of days between two dates.

eg given 2009-01-01 and 2009-01-13 it would return

相关标签:
20条回答
  • 2020-11-22 01:04

    I needed a list with all months between 2 dates for statistics. The 2 dates are the start and enddate from a subscription. So the list shows all months and the amount of subscriptions per month.

    MYSQL

    CREATE PROCEDURE `get_amount_subscription_per_month`()
    BEGIN
       -- Select the ultimate start and enddate from subscribers
       select @startdate := min(DATE_FORMAT(a.startdate, "%Y-%m-01")), 
              @enddate := max(DATE_FORMAT(a.enddate, "%Y-%m-01")) + interval 1 MONTH
       from subscription a;
    
       -- Tmp table with all months (dates), you can always format them with DATE_FORMAT) 
       DROP TABLE IF EXISTS tmp_months;
       create temporary table tmp_months (
          year_month date,
          PRIMARY KEY (year_month)
       );
    
    
       set @tempDate=@startdate;  #- interval 1 MONTH;
    
       -- Insert every month in tmp table
       WHILE @tempDate <= @enddate DO
         insert into tmp_months (year_month) values (@tempDate);
         set @tempDate = (date(@tempDate) + interval 1 MONTH);
       END WHILE;
    
       -- All months
       select year_month from tmp_months;
    
       -- If you want the amount of subscription per month else leave it out
       select mnd.year_month, sum(subscription.amount) as subscription_amount
       from tmp_months mnd
       LEFT JOIN subscription ON mnd.year_month >= DATE_FORMAT(subscription.startdate, "%Y-%m-01") and mnd.year_month <= DATE_FORMAT(subscription.enddate, "%Y-%m-01")
       GROUP BY mnd.year_month;
    
     END
    
    0 讨论(0)
  • 2020-11-22 01:04

    You can use this

    SELECT CAST(cal.date_list AS DATE) day_year
    FROM (
      SELECT SUBDATE('2019-01-01', INTERVAL 1 YEAR) + INTERVAL xc DAY AS date_list
      FROM (
            SELECT @xi:=@xi+1 as xc from
            (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) xc1,
            (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) xc2,
            (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) xc3,
            (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) xc4,
            (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) xc5,
            (SELECT @xi:=-1) xc0
        ) xxc1
    ) cal
    WHERE cal.date_list BETWEEN '2019-01-01' AND '2019-12-31'
    ORDER BY cal.date_list DESC;
    
    0 讨论(0)
  • 2020-11-22 01:06
    CREATE FUNCTION [dbo].[_DATES]
    (
        @startDate DATETIME,
        @endDate DATETIME
    )
    RETURNS 
    @DATES TABLE(
        DATE1 DATETIME
    )
    AS
    BEGIN
        WHILE @startDate <= @endDate
        BEGIN 
            INSERT INTO @DATES (DATE1)
                SELECT @startDate   
        SELECT @startDate = DATEADD(d,1,@startDate) 
        END
    RETURN
    END
    
    0 讨论(0)
  • 2020-11-22 01:13

    I've been fighting with this for quite a while. Since this is the first hit on Google when I searched for the solution, let me post where I've gotten so far.

    SET @d := '2011-09-01';
    SELECT @d AS d, cast( @d := DATE_ADD( @d , INTERVAL 1 DAY ) AS DATE ) AS new_d
      FROM [yourTable]
      WHERE @d <= '2012-05-01';
    

    Replace [yourTable] with a table from your database. The trick is that the number of rows in the table you select must be >= the number of dates you want to be returned. I tried using the table placeholder DUAL, but it would only return one single row.

    0 讨论(0)
  • 2020-11-22 01:13
    DELIMITER $$  
    CREATE PROCEDURE popula_calendario_controle()
       BEGIN
          DECLARE a INT Default 0;
          DECLARE first_day_of_year DATE;
          set first_day_of_year = CONCAT(DATE_FORMAT(curdate(),'%Y'),'-01-01');
          one_by_one: LOOP
             IF dayofweek(affffdate(first_day_of_year,a)) <> 1 THEN
                INSERT INTO calendario.controle VALUES(null,150,affffdate(first_day_of_year,a),affffdate(first_day_of_year,a),1);
             END IF;
             SET a=a+1;
             IF a=365 THEN
                LEAVE one_by_one;
             END IF;
          END LOOP one_by_one;
    END $$
    

    this procedure will insert all dates from the beginning of the year till now, just substitue the days of the "start" and "end", and you are ready to go!

    0 讨论(0)
  • 2020-11-22 01:14

    I would use this stored procedure to generate the intervals you need into the temp table named time_intervals, then JOIN and aggregate your data table with the temp time_intervals table.

    The procedure can generate intervals of all the different types you see specified in it:

    call make_intervals('2009-01-01 00:00:00','2009-01-10 00:00:00',1,'DAY')
    .
    select * from time_intervals  
    .
    interval_start      interval_end        
    ------------------- ------------------- 
    2009-01-01 00:00:00 2009-01-01 23:59:59 
    2009-01-02 00:00:00 2009-01-02 23:59:59 
    2009-01-03 00:00:00 2009-01-03 23:59:59 
    2009-01-04 00:00:00 2009-01-04 23:59:59 
    2009-01-05 00:00:00 2009-01-05 23:59:59 
    2009-01-06 00:00:00 2009-01-06 23:59:59 
    2009-01-07 00:00:00 2009-01-07 23:59:59 
    2009-01-08 00:00:00 2009-01-08 23:59:59 
    2009-01-09 00:00:00 2009-01-09 23:59:59 
    .
    call make_intervals('2009-01-01 00:00:00','2009-01-01 02:00:00',10,'MINUTE')
    . 
    select * from time_intervals
    .  
    interval_start      interval_end        
    ------------------- ------------------- 
    2009-01-01 00:00:00 2009-01-01 00:09:59 
    2009-01-01 00:10:00 2009-01-01 00:19:59 
    2009-01-01 00:20:00 2009-01-01 00:29:59 
    2009-01-01 00:30:00 2009-01-01 00:39:59 
    2009-01-01 00:40:00 2009-01-01 00:49:59 
    2009-01-01 00:50:00 2009-01-01 00:59:59 
    2009-01-01 01:00:00 2009-01-01 01:09:59 
    2009-01-01 01:10:00 2009-01-01 01:19:59 
    2009-01-01 01:20:00 2009-01-01 01:29:59 
    2009-01-01 01:30:00 2009-01-01 01:39:59 
    2009-01-01 01:40:00 2009-01-01 01:49:59 
    2009-01-01 01:50:00 2009-01-01 01:59:59 
    .
    I specified an interval_start and interval_end so you can aggregate the 
    data timestamps with a "between interval_start and interval_end" type of JOIN.
    .
    Code for the proc:
    .
    -- drop procedure make_intervals
    .
    CREATE PROCEDURE make_intervals(startdate timestamp, enddate timestamp, intval integer, unitval varchar(10))
    BEGIN
    -- *************************************************************************
    -- Procedure: make_intervals()
    --    Author: Ron Savage
    --      Date: 02/03/2009
    --
    -- Description:
    -- This procedure creates a temporary table named time_intervals with the
    -- interval_start and interval_end fields specifed from the startdate and
    -- enddate arguments, at intervals of intval (unitval) size.
    -- *************************************************************************
       declare thisDate timestamp;
       declare nextDate timestamp;
       set thisDate = startdate;
    
       -- *************************************************************************
       -- Drop / create the temp table
       -- *************************************************************************
       drop temporary table if exists time_intervals;
       create temporary table if not exists time_intervals
          (
          interval_start timestamp,
          interval_end timestamp
          );
    
       -- *************************************************************************
       -- Loop through the startdate adding each intval interval until enddate
       -- *************************************************************************
       repeat
          select
             case unitval
                when 'MICROSECOND' then timestampadd(MICROSECOND, intval, thisDate)
                when 'SECOND'      then timestampadd(SECOND, intval, thisDate)
                when 'MINUTE'      then timestampadd(MINUTE, intval, thisDate)
                when 'HOUR'        then timestampadd(HOUR, intval, thisDate)
                when 'DAY'         then timestampadd(DAY, intval, thisDate)
                when 'WEEK'        then timestampadd(WEEK, intval, thisDate)
                when 'MONTH'       then timestampadd(MONTH, intval, thisDate)
                when 'QUARTER'     then timestampadd(QUARTER, intval, thisDate)
                when 'YEAR'        then timestampadd(YEAR, intval, thisDate)
             end into nextDate;
    
          insert into time_intervals select thisDate, timestampadd(MICROSECOND, -1, nextDate);
          set thisDate = nextDate;
       until thisDate >= enddate
       end repeat;
    
     END;
    

    Similar example data scenario at the bottom of this post, where I built a similar function for SQL Server.

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