获取日期的两个日期之间的列表

问题描述 投票:85回答:19

使用标准的MySQL的功能是有编写一个查询将返回两个日期之间的天列表的方式。

如给予2009-01-01 2009-01-13并且它会返回一个列表中的值:

 2009-01-01 
 2009-01-02 
 2009-01-03
 2009-01-04 
 2009-01-05
 2009-01-06
 2009-01-07
 2009-01-08 
 2009-01-09
 2009-01-10
 2009-01-11
 2009-01-12
 2009-01-13

编辑:看来我还没有明确。我要生成此列表。我已经存储在数据库中(按日期时间)值,但希望他们能够在左外聚集一起为上述日期的列表(我从一些这方面加入了一些日子右侧空预期,并会处理这)。

mysql sql date gaps-and-islands
19个回答
65
投票

我会用这个存储过程来产生,你需要到临时表命名time_intervals间隔,然后再加入并与临时time_intervals表汇总数据表。

该程序可以生成所有你看到它规定了不同类型的间隔:

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;

this post的底部,在那里我为SQL Server中的类似功能类似的例子数据的情况。


1
投票

我们用这个在我们的人力资源管理系统,你会发现它很有用

SELECT CAST(DAYNAME(daydate) as CHAR) as dayname,daydate
    FROM
    (select CAST((date_add('20110101', interval H.i*100 + T.i*10 + U.i day) )as DATE) as daydate
      from erp_integers as H
    cross
      join erp_integers as T
    cross
      join erp_integers as U
     where date_add('20110101', interval H.i*100 + T.i*10 + U.i day ) <= '20110228'
    order
        by daydate ASC
        )Days

1
投票

该解决方案正在与MySQL 5.0 创建一个表 - mytable。 该模式没有材料。重要的是在它的行数。 所以,你可以只保留一个INT型列10行,值 - 1到10。

SQL:

set @tempDate=date('2011-07-01') - interval 1 day;
select
date(@tempDate := (date(@tempDate) + interval 1 day)) as theDate
from mytable x,mytable y
group by theDate
having theDate <= '2011-07-31';

限制:通过上面的查询返回的日期的最大数量会 (rows in mytable)*(rows in mytable) = 10*10 = 100.

您可以通过SQL改变组成部分增加此范围: 从MYTABLE的x,MYTABLE Y,MYTABLEž 因此,范围是10*10*10 =1000等。


0
投票

创建一个存储过程,它需要两个参数a_begin和a_end。创建一个临时表中它称为T,声明一个变量d分配到a_begin d和运行WHILE循环INSERTing d为T和调用ADDDATE功能来增加值d。最后SELECT * FROM t


0
投票

我会用类似这样:

DECLARE @DATEFROM AS DATETIME
DECLARE @DATETO AS DATETIME
DECLARE @HOLDER TABLE(DATE DATETIME)

SET @DATEFROM = '2010-08-10'
SET @DATETO = '2010-09-11'

INSERT INTO
    @HOLDER
        (DATE)
VALUES
    (@DATEFROM)

WHILE @DATEFROM < @DATETO
BEGIN

    SELECT @DATEFROM = DATEADD(D, 1, @DATEFROM)
    INSERT 
    INTO
        @HOLDER
            (DATE)
    VALUES
        (@DATEFROM)
END

SELECT 
    DATE
FROM
    @HOLDER

然后@HOLDER变量表保存在这两个日期,准备在你的心内容加入之间日益增加的所有日期。


0
投票

我一直在争取与此相当长一段时间。由于这是在谷歌的第一击,当我搜索的解决方案,让我在那里后我到目前为止得到。

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';

从你的数据库中的表更换[yourTable]。诀窍是,在您选择必须是表的行数> =要返回你想要的日期数。我尝试使用表占位符DUAL,但它只会返回一个单行。


0
投票
select * from table_name where col_Date between '2011/02/25' AND DATEADD(s,-1,DATEADD(d,1,'2011/02/27'))

这里,首先,每天添加到当前结束日期,这将是2011-02-28 00:00:00,那么你减去一秒钟,使最终日期2011-02-27 23:59:59。通过这样做,你可以得到所有给定的间隔之间的日期。

输出: 2011/02/25 2011/02/26 2011/02/27


0
投票
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(adddate(first_day_of_year,a)) <> 1 THEN
            INSERT INTO calendario.controle VALUES(null,150,adddate(first_day_of_year,a),adddate(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 $$

这个过程将插入从今年开始所有日期到现在,只是substitue的“开始”日期和“结束”了,你准备好了!


0
投票

我需要用2日期间统计所有月份的列表。 2个日期从预订开始日期和结束日期。因此,列表显示所有个月,每月的订阅量。

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
投票

在使用MariaDB的新递归(通用表表达式)功能优雅溶液> = 10.3和MySQL> = 8.0。

WITH RECURSIVE t as (
    select '2019-01-01' as dt
  UNION
    SELECT DATE_ADD(t.dt, INTERVAL 1 DAY) FROM t WHERE DATE_ADD(t.dt, INTERVAL 1 DAY) <= '2019-04-30'
)
select * FROM t;

上述返回的日期“2019年1月1日”和“二零一九年四月三十零日”之间的表。


-1
投票

我使用Server version: 5.7.11-log MySQL Community Server (GPL)

现在,我们将在一个简单的方法解决这个问题。

我创建了一个名为表“datetable”

mysql> describe datetable;
+---------+---------+------+-----+---------+-------+
| Field   | Type    | Null | Key | Default | Extra |
+---------+---------+------+-----+---------+-------+
| colid   | int(11) | NO   | PRI | NULL    |       |
| coldate | date    | YES  |     | NULL    |       |
+---------+---------+------+-----+---------+-------+
2 rows in set (0.00 sec)

现在,我们将看到中插入的记录。

mysql> select * from datetable;
+-------+------------+
| colid | coldate    |
+-------+------------+
|   101 | 2015-01-01 |
|   102 | 2015-05-01 |
|   103 | 2016-01-01 |
+-------+------------+
3 rows in set (0.00 sec)

在这里我们查询两个日期,而不是这些日期内提取记录。

mysql> select * from datetable where coldate > '2015-01-01' and coldate < '2016-01-01';
+-------+------------+
| colid | coldate    |
+-------+------------+
|   102 | 2015-05-01 |
+-------+------------+
1 row in set (0.00 sec)

希望这将帮助很多的人。


28
投票

对于MSSQL您可以使用此。这是非常快的。

您可以在表值函数或存储过程这个包裹起来,在开始和结束日期作为变量分析。

DECLARE @startDate DATETIME
DECLARE @endDate DATETIME

SET @startDate = '2011-01-01'
SET @endDate = '2011-01-31';

WITH dates(Date) AS 
(
    SELECT @startdate as Date
    UNION ALL
    SELECT DATEADD(d,1,[Date])
    FROM dates 
    WHERE DATE < @enddate
)

SELECT Date
FROM dates
OPTION (MAXRECURSION 0)
GO

13
投票

我们有一个类似的问题与BIRT报表中,我们希望在那些日子里没有数据报告。由于有这些日期内没有记录,对于我们最简单的解决方案是创建一个存储所有的日期一个简单的表格,并用它来获取范围或加入以获得零个值该日期。

我们有运行每月保证表填充5年全力投入未来的工作。该表是这样产生:

create table all_dates (
    dt date primary key
);

毫无疑问,有神奇的棘手的方式与不同DBMS”要做到这一点,但我们总是选择最简单的解决方案。该表的存储要求是最小的,它使查询,以便更简单,便于携带。这种类型的解决方案几乎总是从点的观点,因为它不需要对数据每行的计算性能更好。

其他选项(和我们以前用过这个)是为了确保有一个在表中的每个日期的条目。我们周期性地扫描表并添加零个条目日期和/或时间并不存在。这可能不是你的情况的一个选项,这取决于存储的数据。

如果你真的认为这是保持填充all_dates表中的麻烦,存储过程是去这将返回一个包含这些日期的数据集的方式。这几乎肯定会慢一些,因为你拥有的每它叫,而不是从表只需拔预先计算的数据的时间来计算的范围内。

但是,说实话,你可以填充表了1000年,没有任何严重的数据存储问题 - 365000 16字节(例如)日期加一个索引复制为安全起见,日期加20%的开销,我粗略估计在约14M [365000 * 16 * 2 * 1.2 = 14016000个字节]),在事物的方案微不足道的表。


12
投票

您可以使用MySQL的user variables是这样的:

SET @num = -1;
SELECT DATE_ADD( '2009-01-01', interval @num := @num+1 day) AS date_sequence, 
your_table.* FROM your_table
WHERE your_table.other_column IS NOT NULL
HAVING DATE_ADD('2009-01-01', interval @num day) <= '2009-01-13'

@num是-1,因为你加它,你使用它的第一次。此外,您不能使用“HAVING date_sequence”,因为这使用户可变增量两次,每次一行。


8
投票

借用this答案的想法,你可以设置为0的表到9,并用它来生成日期的列表。

CREATE TABLE num (i int);
INSERT INTO num (i) VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9);

select adddate('2009-01-01', numlist.id) as `date` from
(SELECT n1.i + n10.i*10 + n100.i*100 AS id
   FROM num n1 cross join num as n10 cross join num as n100) as numlist
where adddate('2009-01-01', numlist.id) <= '2009-01-13';

这将允许你产生高达1000日期列表。如果你需要去大,你可以添加另一个交叉连接到内部查询。


3
投票

对于Access(或任何SQL语言)

  1. 创建具有2场一个表,我们将调用此表tempRunDates: --fields fromDatetoDate --Then只插入1的记录,具有开始日期和结束日期。
  2. 创建一个表:Time_Day_Ref --import日期的名单(名单在Excel中很容易)到这个表。 在我的情况--The字段名称是Greg_Dt,为公历日期 - 我通过2020年1月1日作出从2009年1月1日我的名单。
  3. 运行查询: SELECT Time_Day_Ref.GREG_DT FROM tempRunDates, Time_Day_Ref WHERE Time_Day_Ref.greg_dt>=tempRunDates.fromDate And greg_dt<=tempRunDates.toDate;

简单!


2
投票

通常人们会使用辅助号码表,你通常保持周围只是此目的,这方面的一些变化:

SELECT *
FROM (
    SELECT DATEADD(d, number - 1, '2009-01-01') AS dt
    FROM Numbers
    WHERE number BETWEEN 1 AND DATEDIFF(d, '2009-01-01', '2009-01-13') + 1
) AS DateRange
LEFT JOIN YourStuff
    ON DateRange.dt = YourStuff.DateColumn

我已经看到了表值函数等的变化

您也可以将日期常设名单。我们必须在我们的数据仓库,以及当天的时间列表。


2
投票

那么如何找到在SQL服务器两个给定日期之间的日期是http://ektaraval.blogspot.com/2010/09/writing-recursive-query-to-find-out-all.html解释


2
投票
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
© www.soinside.com 2019 - 2024. All rights reserved.