MySQL选择每个组中第一个、第二个和最后一个值的最佳方法
我尝试使用MySQL获取表中每个组的第一个、第二个和最后一个值。我的数据行如下所示:MySQL选择每个组中第一个、第二个和最后一个值的最佳方法,mysql,Mysql,我尝试使用MySQL获取表中每个组的第一个、第二个和最后一个值。我的数据行如下所示: userID purchaseTime ---------------------- 1 2018-01-01 1 2018-01-02 1 2018-01-03 1 2018-01-04 2 2018-02-01 2 2018-02-02 3 2018-03-01 预期结果将是: userI
userID purchaseTime
----------------------
1 2018-01-01
1 2018-01-02
1 2018-01-03
1 2018-01-04
2 2018-02-01
2 2018-02-02
3 2018-03-01
预期结果将是:
userID first second last
------------------------------------------------
1 2018-01-01 2018-01-02 2018-01-04
2 2018-02-01 2018-02-02 2018-02-02
3 2018-03-01 null 2018-03-01
在谷歌搜索了半天之后,我只能想出一个愚蠢的方法,分别执行以下两个查询,然后用我的服务器端代码合并结果:
//get 1st, 2nd values
SELECT userID, purchaseTime
FROM purchaseLog t1
WHERE
(
SELECT COUNT(*)
FROM purchaseLog t2
WHERE t2.userID = t1.userID AND
t2.purchaseTime<= t1.purchaseTime
) <= 2 order by t1.userID , t1.purchaseTime;
//get last value
SELECT max(purchaseTime) FROM purchaseTime GROUP BY userID
我敢肯定,一定有一种更优雅的方法可以一次性获得结果。有人能帮我达到我的要求吗?谢谢大家! 以下代码未经测试,但应该会给您一个好主意:
SELECT
t1.userID,
t1.purchaseTime AS first,
t2.purchaseTime AS `second`,
t4.purchaseTime AS last
FROM purchaseLog t1
LEFT JOIN purchaseLog t0 ON t1.userID = t0.userID AND t0.purchaseTime < t1.purchaseTime
LEFT JOIN purchaseLog t2 ON t1.userID = t2.userID AND t1.purchaseTime < t2.purchaseTime
LEFT JOIN purchaseLog t3 ON t1.userID = t3.userID AND t1.purchaseTime < t3.purchaseTime
AND t3.purchaseTime < t2.purchaseTime
JOIN purchaseLog t4 ON t1.userID = t4.userID AND t1.purchaseTime <= t4.purchaseTime
LEFT JOIN purchaseLog t5 ON t1.userID = t5.userID AND t4.purchaseTime < t5.purchaseTime
WHERE t0.purchaseTime IS NULL AND t3.purchaseTime IS NULL AND t5.purchaseTime IS NULL
让我一步一步地把它分解:
首先,我获取所有不存在相同userID的较早行的行:
SELECT
t1.userID,
t1.purchaseTime AS first
FROM purchaseLog t1
LEFT JOIN purchaseLog t0 ON t1.userID = t0.userID AND t0.purchaseTime < t1.purchaseTime
WHERE t0.purchaseTime IS NULL
接下来,我获取purchaseTime大于第一个purchaseTime的所有行,其中没有purchaseTime介于两者之间的行:
SELECT
t1.userID,
t2.purchaseTime AS `second`
FROM purchaseLog t1
LEFT JOIN purchaseLog t2 ON t1.userID = t2.userID AND t1.purchaseTime < t2.purchaseTime
LEFT JOIN purchaseLog t3 ON t1.userID = t3.userID AND t1.purchaseTime < t3.purchaseTime
AND t3.purchaseTime < t2.purchaseTime
WHERE t3.purchaseTime IS NULL
最后,我得到purchaseTime大于或等于第一行的行,其中不存在更大的purchaseTime:
SELECT
t1.userID,
t4.purchaseTime AS last
FROM purchaseLog t1
JOIN purchaseLog t4 ON t1.userID = t4.userID AND t1.purchaseTime <= t4.purchaseTime
LEFT JOIN purchaseLog t5 ON t1.userID = t5.userID AND t4.purchaseTime < t5.purchaseTime
WHERE t5.purchaseTime IS NULL
将它们组合到一个查询中,即可得到上述答案。好吧,您可能可以这样做: 选择第一个、第二个和最后一个语句,然后将它们连接在一起:
SELECT a.userID, a.purchaseTime
FROM fsl a WHERE a.purchaseTime =
(SELECT MAX(b.purchaseTime) FROM fsl b WHERE b.userID = a.userID)
SELECT a.userID, a.purchaseTime
FROM fsl a WHERE a.purchaseTime =
(SELECT MAX(c.purchaseTime) FROM fsl c
WHERE c.purchaseTime < (SELECT MAX(b.purchaseTime)
FROM fsl b WHERE b.userID = a.userID));
SELECT a.userID, a.purchaseTime
FROM fsl a WHERE a.purchaseTime =
(SELECT MIN(b.purchaseTime)
FROM fsl b WHERE b.userID = a.userID)
并使用连接将其拼接在一起:
SELECT fst.userID as userID, fst.purchaseTime as first, snd.purchaseTime as snd, trd.purchaseTime as last FROM
(SELECT a.userID, a.purchaseTime
FROM fsl a
WHERE a.purchaseTime =
(SELECT MAX(b.purchaseTime) FROM fsl b WHERE b.userID = a.userID)) fst
JOIN (SELECT a.userID, a.purchaseTime FROM fsl a
WHERE a.purchaseTime = (SELECT MAX(c.purchaseTime)
FROM fsl c WHERE c.purchaseTime < (SELECT MAX(b.purchaseTime)
FROM fsl b WHERE b.userID = a.userID))) snd
ON fst.userID = snd.userID
JOIN (SELECT a.userID, a.purchaseTime
FROM fsl a WHERE a.purchaseTime =
(SELECT MIN(b.purchaseTime) FROM fsl b WHERE b.userID = a.userID)) trd
ON trd.userID = snd.userID;
然而,我不能保证这对于任何类型的生产使用都足够快 我很困惑,在输入的情况下,你是如何得到期望的结果的。那么第一个应该是各自ID的最早购买时间,第二个应该是中间时间,第三个应该是最晚的购买时间?您的第一行似乎是这样的,但您的其他两行与之不匹配,所以我猜这不是您想要的?可以将上述内容组合到一个查询中,但我认为这不是一个真正有效的查询。@Obsidiage希望这个解释更清楚:在我的要求中,如果用户在表中有3个以上的购买日志,则字段last将是该用户的最后购买时间。如果一个用户只有一个购买日志,最后一个字段将与第一个字段相同,因为只有一个日志属于该用户,所以购买时间是第一个和最后一个。@Obsidian对于我来说似乎很清楚,因为我给了我一个提示,我现在就要研究它!虽然这可能需要我的时间,因为我是mysql的新手,无论如何,谢谢你!这是一个非常聪明的解决方案,给了我一些我一直在寻找的东西。谢谢你给我的帮助。在这一刻,响应时间不是我的首要任务,我会花时间研究你给出的答案,谢谢!