2016-05-31 9 views
3

私はLIMITing a SQL JOINに似た問題がありますが、やや複雑な要件があります。JOIN条件で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人のユーザが、返されます。

の特定の時間範囲に少なくとも1つの関連する取引を持つ10人のユーザーを返信します。

どのように私はこれをMySQLを使用して達成できますか?

答えて

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を使用して制御できます。あなたは変数を使用せずにこれを行うことができます

+0

ありがとうございました、これは実際には、2番目の 'IF()'の終わりに欠落している閉じ括弧を除いて動作します。 2つの副選択のパフォーマンスに影響はありますか? – Benjamin

+0

また、もう少し考えてみると、MySQLは元のJOINの完全な結果(すべての行)を読み込む必要があります(おそらく一時テーブルですか?)。外側SELECT。これは、多くのユーザーがいる場合にはパフォーマンス上の大きなボトルネックにはなりません。 – Benjamin

+0

@Benjamin提案されたすべてのクエリを実際のデータでテストし、どのように比較するかを教えてください。 –

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 <= ?; 

EDIT:最初

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)である。

+0

ありがとう、私は自分自身を変数ベースのクエリが好きではないですが、JOINを繰り返すことは、特にクエリがより複雑になり、特にそうであれば、もっと厄介です。とにかく、JOINを繰り返すとパフォーマンスにどのような影響がありますか? MySQLは仕事を二度やらなければならないのですか、どこかでパフォーマンスの最適化が行われていますか? – Benjamin