解决此问题的一种方法是使用经典的“返回缺失行”查询。基本上,要获得从数据库返回的“缺失”行,您需要一种生成“缺失”行的方法。
要构建这样的查询,我们可以从以下开始:
SELECT MAX(t.upload_date)
FROM mytable t
WHERE t.upload_date <= NOW()
AND t.user = 'someuser'
这获得了初始日期,我们将从该日期开始向后工作。
对于“每天一个”的要求,您可能希望将 upload_date 截断到午夜,至少对于此查询。现在,我们假设 SELECT 列表中的表达式已经被截断,以说明该方法,而不会陷入处理 unix 时间戳的细节。
要生成日期的降序列表,从上一个查询检索到的初始日期开始...
SELECT s.upload_date - INTERVAL n.d DAY AS available_date
FROM ( SELECT MAX(t.upload_date) AS upload_date
FROM mytable t
WHERE t.upload_date <= NOW()
AND t.user = 'someuser'
) s
CROSS
JOIN ( SELECT 0 AS d UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6
UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9
) n
ORDER BY n.d DESC
有了这个结果,我们可以使用反连接模式来查找尚未使用的日期。这是一个 LEFT JOIN 和一个抛出匹配行的谓词:
SELECT s.upload_date - INTERVAL n.d DAY AS available_date
FROM ( SELECT MAX(t.upload_date) AS upload_date
FROM mytable t
WHERE t.upload_date <= NOW()
AND t.user = 'someuser'
) s
CROSS
JOIN ( SELECT 0 AS d UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6
UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9
) n
LEFT
JOIN mytable u
ON u.upload_date = s.upload_date - INTERVAL n.d DAY
AND u.user = 'someuser'
WHERE u.upload_date IS NULL
ORDER BY n.d DESC
LIMIT 1
这只回顾 9 天,要让它回顾更多天,只需扩展别名为 n 的内联视图以返回更多连续整数。(我们可以使用一些技巧来使用交叉连接来获得一大堆整数。)
剩下的就是处理“匹配”标准(适用于 MySQL DATE 数据类型):
ON u.upload_date = s.upload_date - INTERVAL n.d DAY
变成这样的东西:
ON u.upload_date >= UNIX_TIMESTAMP(FROM_UNIXTIME(s.upload_date)-INTERVAL n.d+1 DAY)
AND u.upload_date < UNIX_TIMESTAMP(FROM_UNIXTIME(s.upload_date)-INTERVAL n.d DAY)
并使用整数时间戳值来获取 MySQL 日期...
SELECT DATE(FROM_UNIXTIME(s.upload_date)) - INTERVAL n.d DAY AS available_date