2

同じテーブル内で 20 の異なる比較を使用する MySQL SELECT クエリがあります。次に例を示します。

SELECT * FROM mytable
WHERE (col1 > (col2 * 0.25))
AND (col5 < col10) .......

返さSCOREれた結果内で呼び出された列の順序に基づいてパーセンタイル ランクを計算しようとしています。SELECT増分行番号を使用COUNT(*)して、株式のランクと返される結果の総数を取得しようとしましたが、一部の結果が同じである場合に同じランクを割り当てる方法がわかりませんSCORE

計算しようとしている式は次のとおりです。

((COUNT(lower scores) + (COUNT(same/tied scores) / 2)) * 100) / COUNT(total results)

その場でパーセンタイルを計算するために、同じ結果行内の低いスコア、同じ/同点のスコア、および合計スコアの数を見つけるにはどうすればよいですか?

アプリケーションの管理者が必要に応じてアプリケーション管理領域内の SELECT ステートメントを調整するようにしたいので、ストアド プロシージャの使用を避けようとしています。

4

3 に答える 3

3

上記のShlomiのコードを使用して、パーセンタイルランクを計算するために私が思いついたコードを次に示します(将来誰かがこれらを計算したい場合に備えて):

SELECT 
    c.id, c.score, ROUND(((@rank - rank) / @rank) * 100, 2) AS percentile_rank
FROM
    (SELECT 
    *,
        @prev:=@curr,
        @curr:=a.score,
        @rank:=IF(@prev = @curr, @rank, @rank + 1) AS rank
    FROM
        (SELECT id, score FROM mytable) AS a,
        (SELECT @curr:= null, @prev:= null, @rank:= 0) AS b
ORDER BY score DESC) AS c;
于 2012-07-29T05:44:12.087 に答える
2

SELECTSQL : Rank without Self Join中のランキングを説明する (私の) 投稿は次のとおりです。

行が反復されている間でもアクセスおよび割り当てられるユーザー定義変数を使用します。

同じロジックを使用して、合計スコア、個別スコアなどの数を含めるように拡張できます。プレビューとして、一般的なクエリを次に示します。

SELECT
  score_id, student_name, score,
  @prev := @curr,
  @curr := score,
  @rank := IF(@prev = @curr, @rank, @rank+1) AS rank
FROM
  score,
  (SELECT @curr := null, @prev := null, @rank := 0) sel1
ORDER BY score DESC
;
于 2012-07-18T14:37:37.627 に答える
1

Shlomi と Zishan (Shlomi のコードを使用) からの応答は、私の大きなテーブルで結果を調べて発見したように、間違いなく正確な結果をもたらしません。他の場所で回答されているように、単一の MySQL クエリでパーセンタイル ランクを計算することは明らかに不可能です: SQL ランク パーセンタイル

ユーザー定義変数を使用する Shlomi Noach アプローチは、最初は、ランキングの上位 2 パーセントではうまく機能しているように見えますが、テーブル内の下位の行ではすぐに機能が低下します。私が行ったように、自分でデータ結果を見てください。

単一の SQL ステートメント内でユーザー定義変数を使用する Shlomi のアプローチがうまくいかない理由について、Roland Bouman によるこのブログ投稿を参照してください。

http://rpbouman.blogspot.com/2009/09/mysql-another-ranking-trick.html

それで、私はこの目的のために Bouman のコードを適応させました。ここに私の解決策があります。これは、必然的に PHP と MySQL を組み合わせたものです。

ステップ 1) 次の 2 つのクエリを送信して、各行の絶対ランクを計算して保存します。

SET @@group_concat_max_len := @@max_allowed_packet;

UPDATE mytable INNER JOIN (SELECT ID, FIND_IN_SET(
    score,
        (SELECT GROUP_CONCAT(
             DISTINCT score
             ORDER BY score  DESC
            )
        FROM mytable)
        ) AS rank
FROM mytable) AS a
ON mytable.ID=a.ID
SET mytable.rank = rank;

ステップ 2: 行の総数を取得します (そして結果を PHP 変数 $total に格納します)

SELECT COUNT(ID) FROM mytable

ステップ 3: PHP ループを使用してテーブルを反復処理し、各行の絶対ランクを使用して行のパーセンタイル ランクを計算します。

3a) ループスルー:

SELECT ID, rank FROM mytable

これらの行の値を PHP で $ID および $rank として保存するとき

3b) 各行の実行について:

$sql = 'UPDATE mytable INNER JOIN (
            SELECT (100*COUNT(ID)/'.$total.') percentile
            FROM mytable
            WHERE rank >= '.$rank.'
        ) a 
        ON mytable.ID = a.ID
        WHERE mytable.ID='.$ID.'
        SET mytable.percentile = a.percentile';

おそらく最も効率的なプロセスではありませんが、間違いなく正確です。私の場合、「スコア」値はあまり頻繁に更新されないため、上記のスクリプトを cron バッチ操作として実行して、パーセンタイル ランクを最新の状態に保ちます。

于 2014-12-25T15:55:18.880 に答える