4

この質問に関連しています。

実際には、 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)
4

1 に答える 1

0

JOIN正当な MYSQL 構文です。うまくいかなかった場合、誰かがそれを答えとしてマークするのではないかと疑ってください。

サブクエリに関しては、最初のソリューションよりも高速ではありません。EXPLAIN PLANこれらのクエリの実行を理解するには、以下を参照することをお勧めします。

同じことを達成する別の方法があります:-

  • -- SOL #3: この投稿で 30 票で回答:

MySQL の ROW_NUMBER()

于 2013-02-01T17:37:11.510 に答える