0

これが私のテーブルへのSQLFiddleリンクです。

numテーブルの最後の 2 つのエントリとfoouserそれぞれの名前である間にゼロ以外の違いがあるため、基本的に Jack と Jill のみを選択したいと考えています。

これはどのように可能ですか?

注: 私のfooテーブルには約 100000 行あるので、データを取得するための非常に迅速かつ高速な方法があればよいでしょう。

4

3 に答える 3

1

オフセットを使用してこれをlimit行い、最新の 2 つの値を取得することをお勧めします。幸いなことに、テーブルにはid順序を決定するための列があります。

select user,
       (select num from foo f2 where f2.user = f.user order by f2.id desc limit 1
       ) lastval,
       (select num from foo f2 where f2.user = f.user order by f2.id desc limit 1, 2
       ) lastval2
from foo f
group by user
having lastval <> lastval2
于 2013-03-28T11:01:22.793 に答える
0

これが1つの方法です(ただし、名前ではなくユーザーのIDでJOINする可能性が高いと思います!?!...

SELECT u.* 
  FROM
     ( SELECT x.*, COUNT(*) rank FROM foo x JOIN foo y ON y.user = x.user AND y.id >= x.id GROUP BY x.id)a
  LEFT
  JOIN
     ( SELECT x.*, COUNT(*) rank FROM foo x JOIN foo y ON y.user = x.user AND y.id >= x.id GROUP BY x.id)b
    ON b.user = a.user 
   AND b.num = a.num
   AND b.rank = a.rank + 1
  JOIN users u
    ON u.user = a.user
 WHERE b.id IS NULL
   AND a.rank = 1;

このクエリは次のように書き直すことができると思います。これはより高速になる可能性があります...

SELECT u.* 
  FROM
     ( SELECT id
            , user
            , num
            , @prev_user := @curr_user
            , @curr_user := user
            , @rank := IF(@prev_user = @curr_user, @rank+1, @rank:=1) rank
         FROM foo
         JOIN (SELECT @curr_user := null, @prev_user := null, @rank := 0) sel1
        ORDER 
           BY user
            , id DESC
     ) a
  LEFT
  JOIN
       ( SELECT id
            , user
            , num
            , @prev_user := @curr_user
            , @curr_user := user
            , @rank := IF(@prev_user = @curr_user, @rank+1, @rank:=1) rank
         FROM foo
         JOIN (SELECT @curr_user := null, @prev_user := null, @rank := 0) sel1
        ORDER 
           BY user
            , id DESC
     ) b
    ON b.user = a.user 
   AND b.num = a.num
   AND b.rank = a.rank + 1
  JOIN users u
    ON u.user = a.user
 WHERE b.id IS NULL
   AND a.rank = 1;
于 2013-03-28T09:05:14.093 に答える
0

Strawberrys 2番目のソリューションに基づいて、これを試しました。

SELECT user, MIN(num) AS MinNum, MAX(num) AS MaxNum
FROM (   SELECT id
            , user
            , num
            , @prev_user := @curr_user
            , @curr_user := user
            , @rank := IF(@prev_user = @curr_user, @rank+1, 1) AS rank
FROM foo
JOIN (SELECT @curr_user := null, @prev_user := null, @rank := 1) sel1
ORDER BY user, id DESC
) AS Sub
WHERE rank <= 2
GROUP BY user
HAVING MinNum != MaxNum

これは、サブセレクトとしてランク付けされた詳細を取得し、ランクが 2 より大きい場所を拒否します (残念ながら、サブセレクト内でこれをチェックしようとすると、ユーザー変数が奇妙な結果をもたらします)。結果はユーザーごとにグループ化され、num の最小値と最大値が返されます。それらが異なる場合、行が返されます (ユーザーごとに 1 行または 2 行しかないため、最小値と最大値は、返される行が 2 つあり、値が異なる場合にのみ異なります)。

これの利点は、2 100000 セットを相互に結合することを回避し、ランキングを 1 回だけ実行する必要があることです (ただし、MySQL がこの 2 つ目の問題を最適化して排除することを望んでいます)。

于 2013-03-28T12:17:02.830 に答える