これが私のテーブルへのSQLFiddleリンクです。
num
テーブルの最後の 2 つのエントリとfoo
がuser
それぞれの名前である間にゼロ以外の違いがあるため、基本的に Jack と Jill のみを選択したいと考えています。
これはどのように可能ですか?
注: 私のfoo
テーブルには約 100000 行あるので、データを取得するための非常に迅速かつ高速な方法があればよいでしょう。
これが私のテーブルへのSQLFiddleリンクです。
num
テーブルの最後の 2 つのエントリとfoo
がuser
それぞれの名前である間にゼロ以外の違いがあるため、基本的に Jack と Jill のみを選択したいと考えています。
これはどのように可能ですか?
注: 私のfoo
テーブルには約 100000 行あるので、データを取得するための非常に迅速かつ高速な方法があればよいでしょう。
オフセットを使用してこれを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
これが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;
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 つ目の問題を最適化して排除することを望んでいます)。