我认为解决这个问题最简单的通用方法是创建一个“序数”表,该表具有您需要的最高行数(在您的情况下为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
到
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
语法。