Mysql生成任意指定两时间范围内的日期列表
Posted SunFlowerXT
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mysql生成任意指定两时间范围内的日期列表相关的知识,希望对你有一定的参考价值。
前言:工作当中有一个场景是数据库存了一些数据,但是日期是零碎的,只有当用户进行了相应日期的操作才会有对应记录的生成。在做所有的数据统计可视化的时候,需要看到的是每一天的日期,此时就需要提供一段时间范围内的所有日期。
在网上查找资料,看到的有三种方法,总结如下:
一、创建存储过程(即创建一个临时的日历表。我是这样理解的),
例一:
以下是我从别人的博客抄过来的例子,这个例子是将日期范围写在创建的逻辑当中,感兴趣的伙伴可以试一下执行,当执行了调用的语句可以查看自己数据库中是否多了一张表。
例二:
这是另外一个创建存储过程,不同于以上的例子,这个可以直接在调用的时候给时间范围。对于日期范围需要和用户交互,需要灵活更改的,这个方法更加适用
DELIMITER $$
DROP PROCEDURE IF EXISTS create_calendar $$
CREATE PROCEDURE create_calendar (s_date DATE, e_date DATE)
BEGIN
SET @createSql = 'CREATE TABLE IF NOT EXISTS calendar (
`date` date NOT NULL,
UNIQUE KEY `unique_date` (`date`) USING BTREE
)ENGINE=InnoDB DEFAULT CHARSET=utf8';
prepare stmt from @createSql;
execute stmt;
WHILE s_date <= e_date DO
INSERT IGNORE INTO calendar VALUES (DATE(s_date)) ;
SET s_date = s_date + INTERVAL 1 DAY ;
END WHILE ;
END$$
DELIMITER ;
CALL create_calendar ('2018-03-01', '2018-12-30');
总结:使用存储过程的优点网上随便一查就能查到,以上这两种方式都能生成一张临时表,里面存放着你自己指定的时间范围内的所有日期。根据自己业务需求,可以选取其中一种方法,生成临时表,再与你的数据进行各种操作得出某段时间范围内日期齐全的数据。
二、(变量控制)指定数据条数,生成连续的数字或日期
例一:
SELECT DATE_FORMAT(DATE_SUB(NOW(), INTERVAL xc DAY), '%Y-%m-%d') as date
FROM (
SELECT @xi:=@xi+1 as xc from
(SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) xc1,
(SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) xc2,
(SELECT @xi:=0) xc0
) xcxc
结果如下所示:
以上代码的作用就是生成当日前25(包括当月)个日的日期。具体解释如下
总结:在如上的例子当中,涉及到的知识点是变量,DATE_SUB(),DATE_FORMAT().使用以上方法的好处就是不用创建存储过程,也不涉及到任何表。缺点就是数据的条数控制并不灵活,不能和用户之间形成互动,即不能自定义日期区间,只能控制数据条数。
三、(利用现有的表做操作)
要求是这个表中的数据足够庞大,好处是不涉及存储过程,不涉及变量,且能自定义日期区间。
select
@num:=@num+1,
date_format(adddate(DATE_SUB('2019-01-17',INTERVAL 1 DAY), INTERVAL @num DAY),'%Y-%m-%d') as date
from order_info,(select @num:=0) t
where adddate('2019-01-17', INTERVAL @num DAY) <= DATE_FORMAT(CURDATE(),'%Y-%m-%d')
order by date;
执行的结果是:
这个是直接把开始时间写成一个固定值的,当然,这个开始时间也类似于一个参数,是可传的,比如我不知道当前表中最开始的时间,那么,我们就只能通过查询出来之后再从当天开始:
select
@num:=@num+1,
date_format(adddate(DATE_SUB((SELECT create_time FROM order_info ORDER BY create_time LIMIT 0,1),INTERVAL 1 DAY), INTERVAL @num DAY),'%Y-%m-%d') as date
from order_info,(select @num:=0) t
where adddate((SELECT create_time FROM order_info ORDER BY create_time LIMIT 0,1), INTERVAL @num DAY) <= (SELECT MAX(create_time) FROM order_info WHERE is_delete =0)
order by date;
这里的起止时间,都是查询当前表中最大和最小的日期,结果如果:
这些sql的具体解释,如下:
还有一种类似的查询方式
SELECT
@date := DATE_ADD( @date, INTERVAL + 1 DAY ) days
FROM
( SELECT @date := DATE_ADD( '2020-08-20', INTERVAL - 1 DAY ) FROM gas_day_schedule_card ) time
WHERE
to_days( @date ) < to_days( '2020-10-05' );
展示结果:
总结:这个是我选择的方法,因为业务需要,我不能用创建存储过程的方法,我主要是做的数据的统计,一些没有产生数据的日期,也需要显示出来,再加上还需要统计别的一些信息,所以我选择的最后这种利用现有的表来查询,再去做自己需要的一些查询。缺点就是必须要有一张现成的表,而且在这么久的长时间使用中,发现可能会出现就算有表,但是获取的时间不全。
四、不用现有的表进行操作,直接传入起始时间和结束时间,进行生成每一天数据
SELECT DATE_FORMAT( date_add(concat('2020-08-20'), interval(help_topic_id) DAY),'%Y-%m-%d') date
FROM mysql.help_topic
WHERE help_topic_id <= timestampdiff(DAY,concat('2020-08-20'),concat('2020-10-05'))
最终的结果是如下图:
总结:这个比较好的就是,不用现有数据库存在任何表,也不用创建存储过程什么的;Mysql没有递归查询,是如何实现指定日期查询的:mysql.help_topic 这时候就可以使用mysql自带的这个表来实现。(算是取巧的方法,暂时没找到更好的方法)
写到这里,也就差不多,以上的几种方法,也是我百度来的,可以根据自己的具体需求选择具体的方法。
以上是关于Mysql生成任意指定两时间范围内的日期列表的主要内容,如果未能解决你的问题,请参考以下文章