我认为该问题最简单的通用解决方案是创建一个Ordinal
具有您需要的最多行数的表(在您的情况下为 31*3 = 93)。
CREATE TABLE IF NOT EXISTS `Ordinal` (
`n` int(10) unsigned NOT NULL AUTO_INCREMENT, PRIMARY KEY (`n`)
);
INSERT INTO `Ordinal` (`n`)
VALUES (NULL), (NULL), (NULL); #etc
接下来,对您的数据执行LEFT JOIN
from 。Ordinal
这是一个简单的案例,上周的每一天:
SELECT CURDATE() - INTERVAL `n` DAY AS `day`
FROM `Ordinal` WHERE `n` <= 7
ORDER BY `n` ASC
你需要改变的两件事是起点和间隔。为了清楚起见,我使用SET @var = 'value'
了语法。
SET @end = CURDATE() - INTERVAL DAY(CURDATE()) DAY;
SET @begin = @end - INTERVAL 3 MONTH;
SET @period = DATEDIFF(@end, @begin);
SELECT @begin + INTERVAL (`n` + 1) DAY AS `date`
FROM `Ordinal` WHERE `n` < @period
ORDER BY `n` ASC;
因此,如果您要加入以获取过去三个月每天的消息数量,最终代码将如下所示:
SELECT COUNT(`msg`.`id`) AS `message_count`, `ord`.`date` FROM (
SELECT ((CURDATE() - INTERVAL DAY(CURDATE()) DAY) - INTERVAL 3 MONTH) + INTERVAL (`n` + 1) DAY AS `date`
FROM `Ordinal`
WHERE `n` < (DATEDIFF((CURDATE() - INTERVAL DAY(CURDATE()) DAY), ((CURDATE() - INTERVAL DAY(CURDATE()) DAY) - INTERVAL 3 MONTH)))
ORDER BY `n` ASC
) AS `ord`
LEFT JOIN `Message` AS `msg`
ON `ord`.`date` = `msg`.`date`
GROUP BY `ord`.`date`
提示和评论:
- 查询中最难的部分可能是确定限制时使用的天数
Ordinal
。相比之下,将整数序列转换为日期很容易。
- 您
Ordinal
可以满足所有不间断序列的需求。只要确保它包含比最长序列更多的行。
- 您可以对多个序列使用多个查询
Ordinal
,例如列出过去七 (1-7) 周的每个工作日 (1-5)。
- 您可以通过在
Ordinal
表格中存储日期来加快速度,但灵活性会降低。这样Ordinal
,无论您使用多少次,您都只需要一张桌子。不过,如果速度值得,请尝试INSERT INTO ... SELECT
语法。