使用PHP / MySQL
我试图创建一个select语句,从当前月份和年份的最少日期获取数据(我用它来显示某个玩家的数据'本月& #39)。月份中的第一个数据可能并不总是存在,因此如果第一个数据未找到,那么它将使用第二个或第三个等等,以最少月份为准。
查询需要类似于:
SELECT * FROM table_name WHERE name = '$username' AND
[...theDate = the least day of data in the current month/year]
它会返回一行数据。
这是我用来获取本周'的一个查询。数据:
SELECT name, data, theDate
FROM table_name
WHERE name = '$username'
AND YEARWEEK(theDate) = YEARWEEK(CURRENT_DATE)
ORDER BY theDate;
答案 0 :(得分:2)
这是一个简单的解决方案:
SELECT a.*
FROM table_name a
INNER JOIN
(
SELECT name, MIN(theDate) AS mindate
FROM table_name
WHERE MONTH(theDate) = MONTH(CURDATE()) AND
YEAR(theDate) = YEAR(CURDATE()) AND
name = '$username'
GROUP BY name
) b ON a.name = b.name AND a.theDate = b.mindate
ORDER BY theDate
内部子选择首先选择当前月份和当前年份的最小日期。这应该只返回一个结果。
外部查询然后加入这一个结果,从而得到当月最早记录日的行&年。
假设每个玩家每天只生成一行,我们可以进一步简化:
SELECT *
FROM table_name
WHERE MONTH(theDate) = MONTH(CURDATE()) AND
YEAR(theDate) = YEAR(CURDATE()) AND
name = '$username'
ORDER BY theDate
LIMIT 1
答案 1 :(得分:1)
如果您只想返回一行,最简单的方法是:
SELECT t.*
FROM table_name t
WHERE t.name = '$username'
AND t.theDate >= CAST(DATE_FORMAT(NOW(),'%Y-%m-01') AS DATE)
AND t.theDate < DATE_ADD(DATE_FORMAT(NOW(),'%Y-%m-01'), INTERVAL 1 MONTH)
ORDER BY s.name DESC, s.theDate DESC
LIMIT 1
ORDER BY基于您({或1}}的前导列上有索引的假设。这将是谓词最合适的索引(即WHERE子句中的条件。我们真的没有必要对(name,theDate)
列进行排序,因为我们知道它将等于某些东西......但是指定了ORDER BY以这种方式使得MySQL更有可能对索引执行反向扫描操作,以正确的顺序返回行,从而避免文件输出操作。
注意:我在WHERE子句的条件中指定了裸name
列,而不是将其包装在任何函数中......通过指定裸列和有界范围,我们使MySQL能够使用索引范围扫描操作。还有其他可能的方法在WHERE子句中包含此条件,例如......
theDate
将返回相同的结果,但像这样的谓词不是可以理解的。也就是说,MySQL不能/不会对索引进行范围扫描以满足这一要求。
如果您打算在一个月内为给定用户获取“最少”日期的所有行(您的问题似乎并不表示您只需要一行),这是获得该结果的一种方式:< / p>
DATE_FORMAT(t.theDate,'%Y-%m') = DATE_FORMAT(NOW(),'%Y-%m')
同样,MySQL可以使用带有前导列(name,theDate)的索引(如果可用)来满足谓词,并执行反向扫描操作(避免排序),并执行JOIN操作。 / p>
注意:我们假设'theDate'是数据类型DATE(没有时间组件)。如果它是DATETIME或TIMESTAMP,则可能存在时间组件,并且如果具有相同“日期”的行的时间组件不同,则该查询可能不会返回给定“日期”值的所有行。 (例如'2012-07-13 17:30'和'2012-07-13 19:55'是不同的日期时间值。)如果我们想要返回这两行(因为两者都是“7月13日”的日期) ,我们需要进行范围扫描而不是相等测试。
SELECT t.*
FROM table_name t
JOIN ( SELECT s.name
, s.theDate
FROM table_name s
WHERE s.name = '$username'
AND s.theDate >= CAST(DATE_FORMAT(NOW(),'%Y-%m-01') AS DATE)
AND s.theDate < DATE_ADD(DATE_FORMAT(NOW(),'%Y-%m-01'), INTERVAL 1 MONTH)
ORDER BY s.name DESC, s.theDate DESC
LIMIT 1
) r
ON r.name = t.name
AND r.theDate = t.theDate
请注意最后两行...我们正在查找SELECT t.*
FROM table_name t
JOIN ( SELECT s.name
, s.theDate
FROM table_name s
WHERE s.name = '$username'
AND s.theDate >= CAST(DATE_FORMAT(NOW(),'%Y-%m-01') AS DATE)
AND s.theDate < DATE_ADD(DATE_FORMAT(NOW(),'%Y-%m-01'), INTERVAL 1 MONTH)
ORDER BY s.name DESC, s.theDate DESC
LIMIT 1
) r
ON t.name = r.name
AND t.theDate >= r.theDate
AND t.theDate < DATE_FORMAT(DATE_ADD(r.theDate,INTERVAL 1 DAY),'%Y-%m-%d')
值大于或等于当前月份的“最小”值并且小于午夜的所有行第二天。