2017-10-31 6 views
1

私は、閉鎖のパーセントでランクされた従業員のリストを生成する必要があります。それはなぜMySQL 5.7の注文は一時ランク列に影響しますか?

| Rank | Employee | Close | Open | Percent| 
|  1| Smith|  9|  1| 0.90| 
|  2| Jones|  75| 25| 0.75| 
|  3|  Zed|  1|  9| 0.10| 
|  3| Adams|  10| 90| 0.10| 

このクエリは、その目的のために動作しますが、それは正しく返すべきではないようにクエリを検討した後、見た目を返し

SET @cnt = 0; 
SET @percent = 2.0; 

SELECT 
    CASE 
     WHEN stats.close/(stats.open+stats.close) = @percent THEN @cnt 
     ELSE (@cnt := @cnt + 1) 
    END rank, 
    stats.employee, 
    stats.close, 
    stats.open, 
    (@percent := stats.close/(stats.open+stats.close)) percent 
     FROM stats 
       WHERE stats.date = CURDATE() 
        ORDER BY percent 

:私は、次のストアドプロシージャを構築しました。これは私がそう思う理由です:

MySQLはORDER BYを処理する前にSELECTを処理します。私はそれによって、MySQLがデータベースから出てきた結果を並べ替えることを決めた順序でランクを割り当てると仮定します。

| Rank | Employee | Close | Open | Percent| 
|  3| Smith|  9|  1| 0.90| 
|  2| Jones|  75| 25| 0.75| 
|  4|  Zed|  1|  9| 0.10| 
|  1| Adams|  10| 90| 0.10| 

なぜこれが当てはまりませんか?

+0

MySQL仕様では、同じステートメントで変数を読み書きすることはできません。 Perconaのプログラマーは、特定のCASEイディオムが現在のビルドのコードに基づいて動作することを発見しました。これはあなたの問題かもしれません:[mcve]を読んで行動してください。 – philipxy

答えて

1

@variablesを使用する順序は厳密には信頼できるものではありませんが、それでもMySQLがまだ欠けている(v8.xのために予定されている、つまりプレリリース版である)ウィンドウ関数を模倣するのは一般的な "ハック"です。

この「ハック」は、ORDER BYがSELECTと一緒に処理されていること(2つの異なるステップではなく)に基づいており、予想以上に統合されています。例えば

SELECT * 
FROM (SELECT CASE 
       WHEN stats.close/(stats.open + stats.close) = @percent THEN 
       @cnt 
       ELSE (@cnt := @cnt + 1) 
       end              rank, 
       stats.employee, 
       stats.close, 
       stats.open, 
       (@percent := stats.close/(stats.open + stats.close)) 
       percent 
     FROM stats 
     CROSS JOIN (@percent := 0 x, @cnt :=0 y) vars 
     WHERE stats.date = Curdate() 
     ORDER BY percent ASC) d 
ORDER BY percent DESC 

インナーためpercent ASCは、外側の順序は、最初の最高パーセントを置く、最低パーセント値から始まるランクを設定します。

実際の問題は、select句内の式の左から右(または上から下へ)のシーケンスが保証されないことです。したがって、@cntを計算するための@percentの比較は、書かれたsqlで示された方法で行われない可能性があります。実際には "ほとんどの時間"動作しますが、そうでないかもしれません。 (窓関数を呼び出す!!

+0

もっと多くの研究をした後、私は必要なものであったカーソルを見つけました。私はカーソルにデータを選択し、結果セットをループし、そのようにランクを割り当てます。 –

関連する問題