我遇到与LIMITing a SQL JOIN类似的问题,但要求稍微复杂一些。
我想搜索位于时间范围内的用户和相关交易:
SELECT u.*, t.*
FROM User u
JOIN Transaction t ON t.user_id = u.id
WHERE t.timestamp >= ? and t.timestamp <= ?;
到目前为止,这么好。现在我想重复查询,但返回的用户数量为LIMIT。但是,对于给定用户返回的事务数量应该没有限制。
如果我按照其他问题中建议的方法,这将转化为:
SELECT u.*, t.*
FROM (SELECT * FROM User LIMIT 10) u
JOIN Transaction t ON t.user_id = u.id
WHERE t.timestamp >= ? and t.timestamp <= ?;
这不会产生我想要的东西:它将返回前10个用户,这些用户可能没有任何关联的交易。
我想要返回10个用户,他们在给定时间范围内至少有一个关联交易。
如何使用MySQL实现这一目标?
答案 0 :(得分:1)
您可以使用变量:
SELECT *
FROM (
SELECT *,
@rn := IF(@uid = user_id, @rn,
IF(@uid := user_id, @rn +1, @rn + 1)) AS rn
FROM (
SELECT u.*, t.*
FROM User u
JOIN Transaction t ON t.user_id = u.id
WHERE t.timestamp >= x and t.timestamp <= y) AS t
CROSS JOIN (SELECT @rn := 0, @uid := 0) AS vars
ORDER BY user_id) AS x
WHERE x.rn <= 10
每次查询返回新用户时,变量@rn
都会加1。因此,我们可以使用@rn <= 10
控制返回的用户数。
答案 1 :(得分:1)
您可以在没有变量的情况下执行此操作,但需要重复join
逻辑:
SELECT u.*, t.*
FROM (SELECT *
FROM User
WHERE EXISTS (SELECT 1
FROM Transaction t
WHERE t.user_id = u.id AND
t.timestamp >= ? and t.timestamp <= ?
)
LIMIT 10
) u JOIN
Transaction t
ON t.user_id = u.id
WHERE t.timestamp >= ? and t.timestamp <= ?;
编辑:
可能最快的答案是这样的:
select u.*, t.*
from (select user_id
from (select user_id
from transaction t
where t.timestamp >= ? and t.timestamp <= ?
limit 1000
) t
limit 30
) tt join
user u
on tt.userid = u.id join
transaction t
on tt.userid = t.userid and t.timestamp >= ? and t.timestamp <= ?;
第一个子查询在事务表中选择1,000个匹配的记录。我的猜测是,这足以让30个用户。然后将此列表连接到用户和事务表以获取最终结果。通过限制列表而不必进行全表扫描,第一个查询应该非常快。 。 。特别是(timestamp, user)
上的附加索引。