[Datenbanken] SQL bzw PL/SQL Quantilberechnung

nightsky99

Grand Admiral Special
Mitglied seit
25.11.2001
Beiträge
2.043
Renomée
19
Standort
Wuppertal
Grüß euch!

Es geht um ein sehr interessantes Problem: ich habe eine Tabelle in meiner Oracle DB, die aus einer einzigen Spalte besteht und worin ca. 10.000 Messwerte stehen.

Jetzt müsste ich daraus zwei Werte extrahieren:
- den Wert von Q25 (also das erste Quartil)
- den Wert von Q75 (das dritte Quartil).

Zur Erklärung, was die Quartile eigentlich sind: wenn die Werte alle der Größe nach geordnet vorliegen, dann ist das erste Quartil das erste Viertel aller Werte, das zwei ist das zweite Viertel aller Werte usw...als Beispiel: ein Array der Größe 100 mit sortierten Zahlen drin: Q25 wäre dann der Wert, an Position 25 des Arrays....Q75 an Stelle 75 usw.

(Aber Achtung: bei einer Arraygröße von 200 wäre Q25 dann Position 50 etc.).


Bei einem Array ist das Vorgehen für Q75 einfach: Position(Arraylänge * 0.75)

Wie geht man aber bei einer SQL Abfrage in effizienter Weise vor?
(Also nicht alle Werte einzeln auslesen, einen Counter erhöhen, den Counter mit der Länge abgleichen etc.)
 
Ich würds entweder über eine stored procedure lösen oder mit order by erstmal die werte aufsteigend sortieren und dann nur noch den wert in gezielt abfragen.

Dürfte in etwa so gehen, das ganze kannst du dann noch schachteln.


1) liefert dir die sortierte Tabelle:

[FONT=Verdana, Arial, Helvetica, sans-serif]SELECT "Spalten_Name"
FROM "Tabellen_Name"
[WHERE "Bedingung"]
ORDER BY "Spalten_Name" ASC

2) liefert die Anzahl der Zeilen der Tabelle, dadurch kannst du dann rausbekommen wo die Zeile 0.75 * count liegt

[/FONT]Select COUNT(Supplier_ID) from suppliers;

Bestimmte Zeile wählen machst du mit Limit - wählt Zeile 23 - da trägst du dann den Wert aus 2) ein
SELECT "Spalten_Name" FROM "Tabellen_Name" LIMIT 23,1
.
EDIT :
.

Alternativ dürfte es wohl auch über RANK gehen.
.
EDIT :
.

Und hier gibts einen fertigen Code (Google mit "SQL quantile")
http://forge.mysql.com/tools/tool.php?id=149
 
Das dürfte relativ einfach machbar sein:
  1. Per Count(*) herausfinden wieviele Werte in der Tabelle drin stehen. Merk dir den Wert auf einem Zettel oder (falls du den Code mehr als einmal ausführen willst) in einer Variable
  2. Mit folgender Query (ungetestet, aber sollte in etwa so aussehen) bekommst du dann deine Ergebnisse:
Code:
SELECT Spalte as Q25
FROM (SELECT Spalte FROM Tabelle ORDER BY Spalte ASC)
WHERE rownum=(count*0.25);
Die Subquery ist nötig damit rownum die richtigen Zeilen anspricht.

Gruß,
Chris

Edit: @JKuehl: LIMIT ist MySQL, bei Oracle wird das per rownum gemacht ;)
 
Also echt mal - ich zerbrech mir da zwei Stunden den Kopf drüber und bei euch gehts so schnell ;D Mir hat die Sache mit der ROWNUM gefehlt, daran kann man sich wirkich schön aufhängen. ;)

Habe es jetzt hinbekommen in leicht modifzierter Form wie Chris_Bear mir es vorgeschlagen hat - die Sache mit dem count funktioniert nicht so ganz direkt, dafür muss nochmal die komplette Subquery rein, die dir den Count zurück liefert. Außerdem muss um alles nochmal eine Query, da du den Rownum Wert so nicht abfragen kannst - und schlussendlich braucht man nochmal eine Query, da beim sortieren der Daten, die ROWNUM Werte ebenfalls verändert werden.

Übersetzt sieht das dann so aus:

Code:
SELECT Q25 FROM(
       SELECT tab1.myvalue AS Q25, ROWNUM _r
       FROM (SELECT Spalte AS myvalue FROM Tabelle ORDER BY Spalte ASC) tab1)

WHERE r_ = ROUND((SELECT COUNT(*) FROM Tabelle) * 0.25)

Vielen Dank euch nochmal! :):) Das gibt ein Bier für euch, wenn ihr mal in der Nähe seid ;D8)

PS: Ihr habt mich vor einem "User Call exceed CPU limit" bewahrt :)
 
Zurück
Oben Unten