2012-07-18 79 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批处理操作,以保持百分比级别最新。