この質問に関連しています。
実際には、 mysqlのグループ化されたランキングの問題を解決したいとは言わないでください。各行がグループに属するエンティティを表すテーブルがあります。グループごとに個別の属性に基づいて、エンティティごとにランクを割り当てます。後で、別の条件を満たす各グループの最初の10個のエンティティを要求するなど、ランクを使用してさまざまな操作を行うことができます。
たとえば、エンティティは、お気に入りのプログラミング言語に応じて異なる「グループ」に属するプログラマーである可能性があります。次に、各プログラマーには評判があります(たとえばフォーラムで)。レピュテーションの降順に基づくプログラマーのランクとなるフィールドを追加します。これは、グループごとに個別に実行したいと思います。
gid | repu | name |
1 1 john
1 3 anna
2 2 scot
2 1 leni
になる
gid | repu | name | rank
1 3 anna 1
1 1 john 2
2 2 scot 1
2 1 leni 2
ここで、セッション変数ベースのソリューションを使用したくないことも要求しましょう。はい、それらはかなりうまく機能しますが、同じステートメントでセッション変数を読み書きしないというmysqlの要求に明らかに違反しています。(ここを参照)
今、この投稿で提案された解決策は言います
-- SOL #1 (SELF-JOIN)
SELECT a.*, count(*) as row_number FROM test a
JOIN test b ON a.gid = b.gid AND a.repu <= b.repu
GROUP BY a.gid, a.repu
これはほとんどのことをします。私が持っているいくつかの質問は、これは正当なSQLですか、それとも標準またはmysqlの癖に違反していますか?mysqlで動作することが保証されていますか?
また、私がここで読んだ別の解決策は、私にとっては黒魔術ですが、よりエレガントに見えます
-- SOL #2 (SUBQUERY)
SELECT t.* ,
( SELECT COUNT(*) + 1
FROM test
WHERE repu > t.repu AND gid = t.gid
) AS rank
FROM test AS t
ORDER BY gid ASC, rank ASC
これは、外部テーブルを参照するサブクエリを使用し、トリックも実行します。誰かがこれがどのように機能するか説明できますか?
また、ここではソリューション#1と同じ質問があります。
さらに、2つの提案されたソリューションのパフォーマンス/互換性の評価に関するコメント。
編集:参考のための追加の方法
この投稿から、セッション変数メソッドの1つのバリエーション。警告:これは避けたいことです。1つのステートメントで、@ randおよび@partitionセッション変数が読み取られ(WHENおよびTHENの後の場合)、書き込まれる(THEN AND ELSEの後のCASEで、および変数を初期化する次のサブクエリでも)ことに注意してください。
-- SOL #3 (SESSION VARIABLES / ANTIPATTERN)
SELECT t.*, ( CASE gid
WHEN @partition THEN @rank := @rank + 1
ELSE @rank := 1 AND @partition := gid ) AS rank
FROM test t,
(SELECT @rank := 0, @partition := '') tmp
ORDER BY gid ASC, repu DESC
また、これは、仲間のベローズによって投稿された、かなり複雑なセットベースのソリューションです。
-- SOL #4 (SET BASED)
SELECT x.*, FIND_IN_SET(CONCAT(x.gid,':',x.repu), y.c) rank
FROM test x
JOIN (
SELECT GROUP_CONCAT(DISTINCT CONCAT(gid,':',repu) ORDER BY gid, repu DESC) c
FROM test GROUP BY gid
) y ON FIND_IN_SET(CONCAT(x.gid,':',x.repu), y.c)