2012-07-18 229 views
2

我有一個MySQL SELECT查詢,它使用同一個表內的20個不同的比較。這裏有一個例子:一個叫做SCORESELECT結果返回MySQL - 動態計算百分位數

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

我想基於列的順序來計算百分等級。我嘗試使用增量行號和COUNT(*)來獲得股票的排名和返回的結果總數,但不知道如何分配相同的排名,其中一些結果具有相同的排名SCORE

下面是我試圖計算公式:

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

如何找到相同的結果行中得分較低,相同/並列得分和總分的數量在運行計算百分?

我試圖避免使用存儲過程,因爲我想我的應用程序的管理員根據需要在我的應用程序管理區域內定製SELECT語句。

回答

3

使用上述施洛米的代碼,這裏的代碼,我想出了計算百分等級(如果有人想在未來計算這些):

SELECT 
    c.id, c.score, ROUND(((@rank - rank)/@rank) * 100, 2) AS percentile_rank 
FROM 
    (SELECT 
    *, 
     @prev:[email protected], 
     @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; 
+0

有沒有簡單的方法將這個語句變成UPDATE語句?例如,假設我在mytable中有一個名爲「percentile」的列,是否有辦法修改語句以將percentile_rank結果存儲在每行的百分列中? – Todd 2013-10-24 18:07:20

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 
; 
+0

嗨Shlomi。感謝您的回覆。這當然有幫助,但它不會提供每行的總排名來計算百分位數。任何想法我可以做到這一點?我在這裏發佈了另一個問題:http://stackoverflow.com/questions/11545537/mysql-selecting-total-results-returned-in-each-row找出來,但仍然沒有得到任何地方。 – Zishan 2012-07-18 19:32:53

+0

爲了簡要說明,請添加其他變量(@total_rank:= @total_rank + @current_rank)。然後使用外部查詢包裝entrie查詢,該查詢現在可以使用rank/@ total_rank。我希望這個簡短的描述有所幫助 – 2012-07-19 04:56:32

+0

謝謝Shlomi,這有幫助! – Zishan 2012-07-29 05:44:29

1

從施洛米和紫山(使用施洛米代碼)的反應絕對不給準確的結果,因爲我被發現檢查結果我的一張桌子。至於其他地方的回答,顯然無法計算在一個MySQL查詢百分等級: SQL rank percentile

使用用戶定義的變量的Shlomi Noach方法確實- 起初 - 看像它的做工精細的頂級幾個百分點的排名,但它很快退化爲表中排名較低的行。像我一樣查看自己的數據結果。

見本博客文章由羅蘭·布曼爲什麼使用一個SQL語句在用戶自定義的變量施洛米的方法是行不通的,有提出更好的解決方案:

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

於是我這是我的解決方案,它必然結合PHP和MySQL:

步驟1)通過提交以下兩個查詢來計算並存儲每行的絕對等級:

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變量$總)

SELECT COUNT(ID) FROM mytable 

步驟3:使用PHP循環通過表來迭代使用絕對通過

3a)的循環::等級爲每一行計算行的百分等級

SELECT ID, rank FROM mytable 

而存儲這些行值如$ ID和PHP

$排名

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批處理操作,以保持百分比級別最新。