我在 MySQL 中有一个非常大的测量数据表,我需要计算每个值的百分位数排名。Oracle 似乎有一个名为percent_rank 的函数,但我找不到MySQL 的类似函数。当然,我可以在 Python 中对其进行暴力破解,无论如何我都会使用它来填充表,但我怀疑这会非常低效,因为一个样本可能有 200.000 个观察值。

有帮助吗?

解决方案

这是一个比较难看的答案,我感到内疚,这样说。这就是说,它可以帮助您解决问题。

确定的比例将计算所有的行,数超过您所提供的数大的行数的一种方法。就可以计算出任何大于或更少,并采取逆是必要的。

创建您数的指标。 总= SELECT COUNT(); less_equal = SELECT COUNT(),其中值> indexed_number;

的百分比会是这样的:less_equal /或总(总 - less_equal)/总

确认他们两人正在使用您创建的索引。如果不是,调整他们,直到他们。该解释的查询应该在右侧栏中“使用索引”。在SELECT COUNT(*)的情况下,应该使用InnoDB的指数,像常量对MyISAM。的MyISAM将知道在任何时候该值,而无需计算。

如果您需要有存储在数据库中的百分比,可以使用安装从上述性能,然后通过使用所述第二查询作为内选择计算每行的值。所述第一查询的值可以被设定为一个常数。

这是否帮助?

雅各

其他提示

下面是一个不同的方法,不需要加入。在我的情况下,行(有15,000表),它运行在约3秒钟。 (join方法采用了一个数量级以上)。

在样品中,假设测量是你计算的百分比排名列,和 ID 仅仅是一个行标识符(不是必需的):

SELECT
    id,
    @prev := @curr as prev,
    @curr := measure as curr,
    @rank := IF(@prev > @curr, @rank+@ties, @rank) AS rank,
    @ties := IF(@prev = @curr, @ties+1, 1) AS ties,
    (1-@rank/@total) as percentrank
FROM
    mytable,
    (SELECT
        @curr := null,
        @prev := null,
        @rank := 0,
        @ties := 1,
        @total := count(*) from mytable where measure is not null
    ) b
WHERE
    measure is not null
ORDER BY
    measure DESC

信用此方法进行到施洛米Noach。他写道:它在这里详细:

http://code.openark.org/blog/mysql/sql-ranking -without-自联接

我在MySQL的测试,这和它的伟大工程;不知道有关Oracle,SQLServer的等

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;

如果您正在使用像PHP程序语言相结合你的SQL,你可以做到以下几点。这个例子过剩飞行挡次分解到机场,到他们的百分位数。采用极限X1,与ORDER BY组合在MySQLÿ条款。不是很漂亮,但做这项工作(对不起挣扎格式化):

$startDt = "2011-01-01";
$endDt = "2011-02-28";
$arrPort= 'JFK';

$strSQL = "SELECT COUNT(*) as TotFlights FROM FIDS where depdt >= '$startDt' And depdt <= '$endDt' and ArrPort='$arrPort'";
if (!($queryResult = mysql_query($strSQL, $con)) ) {
    echo $strSQL . " FAILED\n"; echo mysql_error();
    exit(0);
}
$totFlights=0;
while($fltRow=mysql_fetch_array($queryResult)) {
    echo "Total Flights into " . $arrPort . " = " . $fltRow['TotFlights'];
    $totFlights = $fltRow['TotFlights'];

    /* 1906 flights. Percentile 90 = int(0.9 * 1906). */
    for ($x = 1; $x<=10; $x++) {
        $pctlPosn = $totFlights - intval( ($x/10) * $totFlights);
        echo "PCTL POSN for " . $x * 10 . " IS " . $pctlPosn . "\t";
        $pctlSQL = "SELECT  (ablk-sblk) as ExcessBlk from FIDS where ArrPort='" . $arrPort . "' order by ExcessBlk DESC limit " . $pctlPosn . ",1;";
        if (!($query2Result = mysql_query($pctlSQL, $con)) ) {
            echo $pctlSQL  . " FAILED\n";
            echo mysql_error();
            exit(0);
        }
        while ($pctlRow = mysql_fetch_array($query2Result)) {
            echo "Excess Block is :" . $pctlRow['ExcessBlk'] . "\n";
        }
    }
}

MySQL 8终于引入了窗口函数,其中, PERCENT_RANK() 您正在寻找的功能。所以,只需写:

SELECT col, percent_rank() OVER (ORDER BY col)
FROM t
ORDER BY col

你的问题提到了“百分位数”,这是一个略有不同的东西。为了完整起见,有 PERCENTILE_DISCPERCENTILE_CONT SQL 标准和某些 RBDMS(Oracle、PostgreSQL、SQL Server、Teradata)中存在逆分布函数,但 MySQL 中没有。借助 MySQL 8 和窗口函数, 你可以效仿 PERCENTILE_DISC, ,但是,再次使用 PERCENT_RANKFIRST_VALUE 窗函数.

要获得排名,我会说,你需要(左)外连接表上本身是这样的:

select t1.name, t1.value, count(distinct isnull(t2.value,0))  
from table t1  
left join table t2  
on t1.value>t2.value  
group by t1.name, t1.value 

有关的每一行,你将计数有多少(如果有的话)相同的表的行具有较低的价格。

请注意,我是比较熟悉SQLSERVER所以语法可能是不对的。另外,不同的可能没有你想达到什么是正确的行为。但是,这是一般的想法。结果 然后我得到了真正的百分等级,你需要先得到一个变量(或取决于你想要采取约定不同值)值的数量和使用上面给出的实际排名计算百分等级。

假设我们有一个销售表,如:

USER_ID,单位

然后下面的查询将给予每个用户的百分位数:

select a.user_id,a.units,
(sum(case when a.units >= b.units then 1 else 0 end )*100)/count(1) percentile
from sales a join sales b ;

请注意,这将去CROSS JOIN所以导致O(n2)的复杂性,以便可以被视为未优化的解决方案,但似乎简单给我们不必在MySQL版本的任何功能。

不知道什么运通过“百分等级”的意思,但要获得一组值的已知百分看到的 http://rpbouman.blogspot.com/2008/07/calculating-nth-percentile-in-mysql.html 在SQL计算可以很容易地被改变,以产生另一个或多重百分

一注:我不得不稍微改变的计算中,例如第90百分位 - “90/100 * COUNT(*)+ 0.5” 而不是 “90/100 * COUNT(*)+ 1”。有时是跳过两个值过去在有序列表中的百分位点,而不是选择为百分下一个更高的价值。也许整数四舍五入在MySQL的工作方式。

即:

... SUBSTRING_INDEX(SUBSTRING_INDEX(GROUP_CONCAT(fieldValue方法ORDER BY fieldValue方法SEPARATOR ' '),', '90/100 * COUNT(*)+的 0.5 ),',', -1)作为90thPercentile ....

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top