我的数据是这样的:
+------------+---------+-------+
| Name | Time | Flag |
+------------+---------+-------+
| Bob | 401 | 1 |
| Bob | 204 | 0 |
| Dan | 402 | 1 |
| Dan | 210 | 0 |
| Jeff | 204 | 0 |
| Fred | 407 | 1 |
| Mike | 415 | 1 |
| Mike | 238 | 0 |
+------------+---------+-------+
我想得到每个人的最佳时间,但如果设置了“旗帜”,他们的时间应该除以2。 例如,Bob的最佳时间是200.5
现在我可以做一个相对简单的查询来获取这样的数据:
SELECT userid,
MIN(CASE WHEN flag = 1 THEN time / 2 ELSE time END) AS convertedTime,
time,
flag
FROM times t
GROUP BY userid
ORDER BY convertedtime ASC
这里的问题是没有为时间和标志返回正确的相应数据,得到这些数据:
Bob 200.5 204 0
而不是正确的数据
Bob 200.5 401 1
当然,我看到了上一个查询的问题,我用它修复了它:
SELECT userid,
MIN(convertedtime) AS convertedTime,
(SELECT time
FROM times
WHERE MIN(convertedtime) = CASE
WHEN flag = 1 THEN time / 2
ELSE time
end
LIMIT 1) AS time,
(SELECT flag
FROM times
WHERE MIN(convertedtime) = CASE
WHEN flag = 1 THEN time / 2
ELSE time
end
LIMIT 1) AS flag
FROM (SELECT userid,
CASE
WHEN flag = 1 THEN time / 2
ELSE time
end AS convertedTime,
time,
flag
FROM times t) AS t
GROUP BY userid
ORDER BY convertedtime ASC
这确实有效,但我觉得必须有一种更好,更有效的方法。在我的实际查询中,我将时间除以2的部分是一个更长的公式,我有数千行,所以它非常慢。
所以问题是,对此有更好/更有效的查询吗?
答案 0 :(得分:1)
使用SQL select only rows with max value on a column中的常用技巧,但在比较flag
条件中的值时添加ON
检查。
SELECT t1.username, t2.convertedtime, t1.time, t1.flag
FROM times AS t1
JOIN (SELECT username,
MIN(IF(flag = 1, time/2, time) AS convertedtime
FROM times
GROUP BY username) AS t2
ON t1.username = t2.username
AND t1.time = IF(t1.flag = 1, t2.convertedtime * 2, t2.convertedtime)
这可能不会非常有效 - 我不认为它可以使用索引进行条件比较。
答案 1 :(得分:0)
这是我最终使用的(在这种情况下,由于我的更复杂的实际查询在其中进行舍入,因此无法乘以2来恢复数字),但Barmar与我做了几乎相同的事情&# 39;这样做我把他标记为答案。
SELECT times.userID, times2.convertedTime, times.time, times.flag
FROM times JOIN
(
SELECT userid,
MIN(CASE WHEN flag = 1 THEN time / 2 ELSE time END) AS convertedTime,
time,
flag
FROM times t
GROUP BY userid
ORDER BY convertedtime ASC
) as times2 ON times.userid = times2.userid AND
(
(times.time / 2 = times2.convertedTime AND times.flag = 1) OR
(times.time = times2.convertedTime AND times.flag = 0)
)