Frage

Ich habe eine sehr große Tabelle von Messdaten in MySQL und ich brauche den Prozentrang für jeden einzelnen dieser Werte zu berechnen. Oracle scheint eine Funktion namens PERCENT_RANK zu haben, aber ich kann nichts Vergleichbares für MySQL finden. Sicher konnte ich nur Brute-Force es in Python, die ich sowieso die Tabelle füllen verwenden, aber ich vermute, dass ziemlich ineffizient wäre, weil eine Probe 200,000 Beobachtungen haben könnte.

War es hilfreich?

Lösung

Dies ist eine relativ hässliche Antwort, und ich fühle mich schuldig, es zu sagen. Das heißt, es können Sie auch mit Ihrem Problem helfen.

Ein Weg, um den Prozentsatz zu bestimmen, wäre alle Zeilen zu zählen, und die Anzahl der Zeilen zählen, die größer ist als die Zahl sind Sie zur Verfügung gestellt. Sie können berechnen entweder größer oder kleiner als und nehmen Sie die inverse wie nötig.

Erstellen Sie einen Index für Ihre Nummer. gesamt = select count (); less_equal = select count (), wo Wert> indexed_number;

Der Prozentsatz wäre so etwas wie: less_equal / total oder (gesamt - less_equal) / total

Stellen Sie sicher, dass sie beide den Index verwenden, die Sie erstellt haben. Wenn sie nicht sind, zwicken sie, bis sie sind. Die Abfrage sollte erklären „mit dem Index“ in der rechten Spalte. Im Falle der select count (*) sollte es mit Index für InnoDB und so etwas wie const für MyISAM sein. MyISAM wird diesen Wert jederzeit wissen, ohne sie zu berechnen ist.

Wenn Sie den Prozentsatz in der Datenbank gespeichert haben, benötigt werden, können Sie das Setup von oben für die Leistung verwenden und dann für jede Zeile den Wert berechnen, indem die zweite Abfrage als Innen wählen verwenden. Der Wert der ersten Abfrage kann als Konstante eingestellt werden.

Ist diese Hilfe?

Jacob

Andere Tipps

Hier ist ein anderer Ansatz, der eine Verknüpfung nicht erforderlich. In meinem Fall (eine Tabelle mit 15.000+) Reihen, läuft es in ca. 3 Sekunden. (Die JOIN-Methode eine Größenordnung länger dauert).

In der Probe sei angenommen, dass Maßnahme ist die Spalte, auf dem Sie den prozentualen Rang zu berechnen und id ist nur ein Zeilenbezeichner (nicht erforderlich):

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

Kredit für diese Methode geht an Shlomi Noach. Er schreibt über sie im Detail hier:

http://code.openark.org/blog/mysql/sql-ranking -ohne-Self-Join

Ich habe dies in MySQL getestet und es funktioniert super; keine Ahnung von Oracle, SQLServer, etc.

gibt es keine einfache Möglichkeit, dies zu tun. finden Sie unter http://rpbouman.blogspot.com/2008 /07/calculating-nth-percentile-in-mysql.html

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;

Wenn Sie Ihre SQL mit einer prozeduralen Sprache wie PHP kombinieren, können Sie die folgenden Aktionen aus. Dieses Beispiel bricht Überschuss Flugblockzeiten in einem Flughafen nach unten in ihre Perzentile. Verwendet das LIMIT x, y-Klausel in MySQL in Kombination mit ORDER BY. Nicht sehr hübsch, aber macht den Job (sorry mit der Formatierung zu kämpfen):

$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 schließlich Fensterfunktionen eingeführt, und unter ihnen, die PERCENT_RANK() Funktion, die Sie gesucht haben. Also, einfach schreiben:

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

Ihre Frage erwähnt „Perzentile“, die eine etwas andere Sache sind. Der Vollständigkeit halber gibt es PERCENTILE_DISC und PERCENTILE_CONT inversen Verteilungsfunktionen in SQL-Standard und in einigen RBDMS (Oracle, PostgreSQL, SQL Server, Teradata), aber nicht in MySQL. Mit MySQL 8 und Fensterfunktionen, Sie können PERCENTILE_DISC emulieren jedoch wieder mit den PERCENT_RANK und FIRST_VALUE Fensterfunktionen .

den Rang zu erhalten, ich würde sagen, Sie müssen (links) äußere Verknüpfung in der Tabelle auf sich selbst so etwas wie:

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 

Für jede Zeile, werden Sie zählen, wie viele (wenn überhaupt) Zeilen derselben Tabelle ein minderwertiges Wert haben.

Beachten Sie, dass ich mit Sqlserver mehr vertraut bin, so dass die Syntax nicht richtig sein könnte. Auch die deutliche kann das richtige Verhalten nicht für das, was Sie erreichen wollen. Aber das ist die allgemeine Idee.
Dann den realen Prozentrang erhalten müssen Sie zuerst die Anzahl der Werte in einer Variablen (oder unterschiedlichen Werten in Abhängigkeit von der Konvention Sie nehmen will) erhalten und den Prozentrang berechnet den realen Rang oben gegeben werden.

Angenommen, wir haben einen Verkaufstisch wie:

user_id, Einheiten

dann Abfrage folgende geben Perzentil der einzelnen Benutzer:

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 ;

Beachten Sie, dass dies für die grenz gehen führt join so in O (n2) Komplexität kann so als nicht optimierte Lösung in Betracht gezogen werden, aber scheint einfach gegeben wir keine Funktion in MySQL Version.

Nicht sicher, was das op von ‚Prozentrang‘ gemeint, sondern eine gegebene Perzentil für eine Reihe von Werten finden Sie unter http://rpbouman.blogspot.com/2008/07/calculating-nth-percentile-in-mysql.html Die SQL-Berechnung leicht geändert werden, könnte eine andere oder mehrere Perzentile zu erzeugen.

Eine Anmerkung: Ich hatte die Berechnung leicht zum Beispiel der 90. Perzentile, ändern - "90/100 * COUNT (*) + 0,5" anstelle von "90/100 * COUNT (*) + 1". Manchmal war es zwei Werte hinter dem Prozentpunkt in der geordneten Liste überspringen, anstatt den nächst höheren Wert für die Perzentil Kommissionierung. Vielleicht ist die Art und Weise integer Werke in mysql Runden.

ie:

.... SUBSTRING_INDEX (SUBSTRING_INDEX (GROUP_CONCAT (fieldvalue ORDER BY fieldvalue SEPARATOR ' '),', ' 90/100 * COUNT (*) + 0.5 ),',', -1) als 90thPercentile ....

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top