mysql两日期间隔年数_关于mysql:获取两个日期之间的日期列表

使用标准的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

编辑:看来我还不清楚。 我想生成这个列表。 我有值存储在数据库中(按日期时间),但是希望它们在左外连接上聚合到上面的日期列表中(我希望在某些连接的右侧有一段时间为null并且会处理这个)。

我认为答案stackoverflow.com/a/2157776/466677中描述了最佳解决方案

从日期范围生成天数的可能重复

我将使用此存储过程在名为time_intervals的临时表中生成所需的时间间隔,然后使用temp time_intervals表JOIN并聚合数据表。

该过程可以生成您在其中指定的所有不同类型的间隔:

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;

这篇文章底部的类似示例数据场景,我为SQL Server构建了一个类似的函数。

我个人希望在PostgreSQL中生成与生成序列类似的东西。

如果要生成一次数据,您甚至可以使用永久表并使用此脚本填充缺少的日期。

我必须在创建过程语句之前更改分隔符,以使其通过phpMyAdmin工作(以避免声明语句上的语法错误) DECLARE // [/ code]

对于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

OPTION(MAXRECURSION 0)有什么用?

我们在BIRT报告中遇到了类似的问题,因为我们想报告那些没有数据的日子。由于这些日期没有条目,对我们来说最简单的解决方案是创建一个存储所有日期的简单表,并使用它来获取范围或连接以获得该日期的零值。

我们每个月都有一份工作,以确保该表在未来5年内填充。因此创建表:

毫无疑问,使用不同的DBMS有一些神奇的棘手方法,但我们总是选择最简单的解决方案。该表的存储要求很小,它使查询更加简单和便携。从性能的角度来看,这种解决方案几乎总是更好,因为它不需要对数据进行每行计算。

另一个选项(我们以前使用过它)是为了确保每个日期在表格中都有一个条目。我们定期清扫表格,并为不存在的日期和/或时间添加零条目。在您的情况下,这可能不是一个选项,它取决于存储的数据。

如果你真的认为保持all_dates表填充是一件麻烦事,那么存储过程就是返回包含这些日期的数据集的方法。这几乎肯定会变慢,因为每次调用时都必须计算范围,而不是仅仅从表中提取预先计算的数据。

但是,说实话,你可以填写表1000年没有任何严重的数据存储问题 - 365,000个16字节(例如)日期加上一个索引重复日期加上20%的安全开销,我粗略估计约14M [365,000 * 16 * 2 * 1.2 = 14,016,000字节]),这是事物计划中的一个小表。

您可以使用MySQL的用户变量,如下所示:

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",因为这会使用户变量每行增加两次。

谢谢,它适合我。

从这个答案借用一个想法,您可以设置一个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个日期的列表。如果需要更大,可以在内部查询中添加另一个交叉连接。

此解决方案效果更好。但它与UNIX_TIMESTAMP()有一个问题 - 它给出的结果如1231185600.000000;小数点后的毫秒部分; while - SELECT UNIX_TIMESTAMP(ADDDATE('2009-01-01',0))AS date;不会导致那部分。

对于Access(或任何SQL语言)

创建一个包含2个字段的表,我们称之为tempRunDates:

- 字段fromDate和toDate

- 然后只插入1条记录,其中包含开始日期和结束日期。

创建另一个表:Time_Day_Ref

- 在此表中导入日期列表(将Excel中的列表很容易)。

- 我的案例中的字段名称是Greg_Dt,格里高利日期

- 我从2009年1月1日到2020年1月1日列出了我的名单。

运行查询:

SELECT Time_Day_Ref.GREG_DT

FROM tempRunDates, Time_Day_Ref

WHERE Time_Day_Ref.greg_dt>=tempRunDates.fromDate And greg_dt<=tempRunDates.toDate;

简单!

通常情况下,人们会使用您通常保留的辅助数字表来实现此目的,并对此进行一些修改:

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

我已经看到了具有表值函数等的变体。

您还可以保留一份永久的日期列表。我们在数据仓库中有这个以及一天中的时间列表。

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

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

MySQL还不支持递归查询,因此这里不能使用此解决方案。

此解决方案适用于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 z

所以,范围是10*10*10 =1000,依此类推。

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

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

创建一个存储过程,它接受两个参数a_begin和a_end。

在其中创建一个名为t的临时表,声明一个变量d,将a_begin指定给d,然后运行WHILE循环INSERT进入t并调用ADDDATE函数来增加值d。最后SELECT * FROM t。

实际上我相信永久表会更好地执行速度(具有最小的存储要求)。将日期预先计算到表中并在需要时提取比在每次需要时创建范围更快。

@Pax,这取决于获得的速度提升是否值得表维护。例如,如果报告生成需要3秒并且运行WHILE循环以生成日期需要0.001秒,那么我认为性能增益是可忽略的。 Knuth:过早的优化是万恶之源。

@ eed3si9n,过早优化,是的,不是所有的优化:-)如果你的例子是正确的那么是的,我同意你的观点,但是应该测量它的确定性。如果您按照我的建议生成1000年(一次性成本),表maint已经消失,但这些秒将加起来。

在MariaDB> = 10.3和MySQL> = 8.0中使用新的递归(公用表表达式)功能的优雅解决方案。

以上内容返回"2019-01-01"和"2019-04-30"之间的日期表。

"选择'2019-01-01'为dt"这个选择器是什么?是否可以只选择一个from和to字段?

我会使用类似的东西:

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变量表保存这两个日期之间按日递增的所有日期,随时准备加入您的心灵内容。

您好,我正在尝试使用代码并将输出插入到我定义DateTest的表中,其中列的日期填充类型为DATETIME ...但是失败...可以提供可以使用的代码吗?注意:在这里使用SQL Server谢谢:)

我已经和它斗争了很长一段时间。由于这是我搜索解决方案时谷歌的第一次打击,让我发布到目前为止我已经到达的位置。

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,但它只返回一行。

有趣的方法。但是..这基本上不是Vihang在上面提出的建议;)?

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

在这里,首先添加一天到当前的endDate,它将是2011-02-28 00:00:00,然后你减去一秒使得结束日期2011-02-27 23:59:59。通过这样做,您可以获得给定间隔之间的所有日期。

输出:

2011/02/25

2011/02/26

2011/02/27

为什么要downvote?如果您不解释,我们该如何学习?

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 $$

这个程序将插入从年初到现在的所有日期,只是替换"开始"和"结束"的日子,你准备好了!

线IF a=365 THEN如何受到闰年的影响?

另外,第9行的数字150有什么意义?这段代码是一个"轻拍答案",没有太多实际解释。

我需要一份包含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

我正在使用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)

希望这会对很多人有所帮助。

在没有任何理由的情况下,这个SQL很好,并且在工作场景中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值