使用JOIN条件限制SQL JOIN

时间:2016-05-31 11:38:08

标签: mysql join sql-limit

我遇到与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实现这一目标?

2 个答案:

答案 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)上的附加索引。