来自 Shlomi 和 Zishan(使用 Shlomi 的代码)的响应肯定不会给出准确的结果,正如我通过在我的一张大表上检查结果发现的那样。正如在其他地方回答的那样,显然不可能在单个 MySQL 查询中计算百分位等级:
SQL rank percentile
使用用户定义变量的 Shlomi Noach 方法确实- 起初 - 看起来对于排名前几个百分比的排名很好,但对于表中排名较低的行,它很快就会退化。像我一样,亲自查看您的数据结果。
请参阅 Roland Bouman 的这篇博客文章,了解为什么 Shlomi在单个 SQL 语句中使用用户定义变量的方法不起作用,并提出了更好的解决方案:
http://rpbouman.blogspot.com/2009/09/mysql-another-ranking-trick.html
因此,我为此目的修改了 Bouman 的代码,这是我的解决方案,它必然结合了 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 变量 $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';
可能不是最有效的过程,但绝对准确,因为在我的情况下,'score' 值不会经常更新,所以我将上述脚本作为 cron 批处理操作运行,以保持百分位数排名最新。