MySQL

2009-06-29 18 views
17

में प्रतिशत रैंक की गणना करना मेरे पास MySQL में माप डेटा की एक बहुत बड़ी तालिका है और मुझे इन मानों में से प्रत्येक के लिए प्रतिशत रैंक की गणना करने की आवश्यकता है। ओरेकल में प्रतिशत_क्रैंक नामक फ़ंक्शन होता है लेकिन मुझे MySQL के लिए कुछ भी नहीं मिल रहा है। निश्चित रूप से मैं इसे पायथन में केवल बलपूर्वक मजबूर कर सकता हूं जिसे मैं टेबल को पॉप्युलेट करने के लिए किसी भी तरह का उपयोग करता हूं लेकिन मुझे संदेह है कि यह काफी अक्षम होगा क्योंकि एक नमूने में 200,000 अवलोकन हो सकते हैं।MySQL

+0

क्या आप कृपया बता सकते हैं कि प्रतिशत प्रतिशत रैंक से आपका क्या मतलब है? –

+0

@AssafLavie: http://en.wikipedia.org/wiki/Percentile_rank – eliasah

+0

मैंने किसी भी प्रतिशत के लिए एक MySQL फ़ंक्शन काम किया: http://stackoverflow.com/a/40266115/1662956 – dartaloufe

उत्तर

1

यह अपेक्षाकृत बदसूरत जवाब है, और मुझे यह कहने में दोषी लगता है। उस ने कहा, यह आपकी समस्या के साथ आपकी मदद कर सकता है।

प्रतिशत निर्धारित करने का एक तरीका सभी पंक्तियों को गिनना होगा, और आपके द्वारा प्रदान की गई संख्या से अधिक पंक्तियों की संख्या को गिनना होगा। आप जितना आवश्यक हो उतना अधिक या उससे कम की गणना कर सकते हैं।

अपनी संख्या पर एक सूचकांक बनाएँ। कुल = चयन गिनती (); less_equal = चयन गिनती () जहां मूल्य> indexed_number; (- less_equal कुल)/कुल

सुनिश्चित करें कि उन दोनों के सूचकांक आपके द्वारा बनाए गए उपयोग कर रहे हैं less_equal/कुल या:

प्रतिशत की तरह कुछ होगा। यदि वे नहीं हैं, तब तक उन्हें ट्विक करें जब तक वे नहीं हैं। स्पष्ट क्वेरी में दाईं ओर कॉलम में "अनुक्रमणिका का उपयोग करना" होना चाहिए। चुनिंदा गिनती (*) के मामले में यह इनो डीबी के लिए इंडेक्स का उपयोग करना चाहिए और माईसाम के लिए कॉन्स जैसे कुछ होना चाहिए। MyISAM इस मूल्य को किसी भी समय इसकी गणना किए बिना जानता होगा।

यदि आपको डेटाबेस में संग्रहीत प्रतिशत होना आवश्यक है, तो आप ऊपर से सेटअप के लिए सेटअप का उपयोग कर सकते हैं और फिर दूसरी क्वेरी का उपयोग आंतरिक चयन के रूप में कर सकते हैं। पहली क्वेरी का मान स्थिर के रूप में सेट किया जा सकता है।

क्या इससे मदद मिलती है?

याकूब

+0

मैंने वास्तव में कुछ हफ्ते पहले कोशिश की और यह अविश्वसनीय रूप से धीमा था इसलिए मैंने पायथन में प्रतिशत की गणना की और डेटाबेस में मूल्य डाला। – lhahne

+0

आपने चयन गिनती (*) का उपयोग करने की कोशिश की और गिनती (*) <= yourvalue का चयन करें? क्या आपने पुष्टि की थी कि उनमें से दोनों को एक इंडेक्स द्वारा संभाला जा रहा था जिसमें केवल आपके लिए आवश्यक कॉलम थे? अगर समाधान डेटा पंक्तियों को स्पर्श करना था, तो मुझे उम्मीद है कि यह तीव्रता के एक या दो आदेश धीमे हो। यदि इंडेक्स में आवश्यक कॉलम से अधिक शामिल है या MySQL की मेमोरी कॉन्फ़िगरेशन सही नहीं है, तो यह बहुत धीमी हो जाएगी। यदि ऐसा है, तो यह तेजी से होना चाहिए था। लगभग "अविश्वसनीय रूप से धीमा" कितना समय है? अपेक्षित प्रतिक्रिया की परिमाण के क्रम के आधार पर, मेरा जवाब अनावश्यक रूप से धीमा हो सकता है। – TheJacobTaylor

+0

@TheJacobTaylor सही उत्तर लेकिन कोड पर छोटा। यदि आप एक कार्यात्मक 'चयन विशिष्ट' प्रकार क्वेरी अप डालते हैं, तो आप मेरा +1 प्राप्त करते हैं। इसके अलावा, अगर आप इसे ठीक कर सकते हैं, तो आपको एक अच्छा चमकदार +1 मिल जाएगा और जांचें! ;)) http://stackoverflow.com/questions/13689434/update-all-rows-with-countdistinct-only-updates- फर्स्ट-row-the-rest-0 –

4

ऐसा करने का कोई आसान तरीका नहीं है। देख http://rpbouman.blogspot.com/2008/07/calculating-nth-percentile-in-mysql.html

+0

जो मैं ढूंढ रहा हूं वह है वास्तव में इसके विपरीत यानी एक संख्या दी गई है, इसे मुझे अपना रैंक बता देना चाहिए। मुझे कुछ हद तक आश्वस्त है कि ओरेकल में यह आसान होगा लेकिन दुर्भाग्यवश यह संभावना नहीं है। – lhahne

0

रैंक पाने के लिए, मैं कहेंगे आप की तरह कुछ पर ही तालिका में शामिल होने के (बाएं) बाहरी की जरूरत है:

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 से अधिक परिचित हूं इसलिए वाक्यविन्यास सही नहीं हो सकता है। जो भी आप हासिल करना चाहते हैं उसके लिए विशिष्ट व्यवहार भी सही नहीं हो सकता है। लेकिन यह सामान्य विचार है।
फिर वास्तविक प्रतिशत रैंक प्राप्त करने के लिए आपको पहले एक वैरिएबल (या उस सम्मेलन के आधार पर अलग-अलग मूल्यों में मूल्यों की संख्या प्राप्त करने की आवश्यकता होगी) और ऊपर दिए गए वास्तविक रैंक का उपयोग करके प्रतिशत रैंक की गणना करना होगा।

2

आप PHP तरह एक प्रक्रियात्मक भाषा के साथ अपने एसक्यूएल मेल कर रहे हैं, तो आप निम्नलिखित कर सकते हैं। यह उदाहरण हवाईअड्डे में अपने प्रतिशत में अतिरिक्त उड़ान ब्लॉक के समय को तोड़ देता है। ORDER BY के साथ संयोजन में MySQL में LIMIT x, y खंड का उपयोग करता है।

$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"; 
     } 
    } 
} 
18

यहाँ एक अलग दृष्टिकोण है कि एक में शामिल होने की आवश्यकता नहीं है है: बहुत सुंदर नहीं है, लेकिन काम (खेद स्वरूपण के साथ संघर्ष किया है)। मेरे मामले में (15,000+ के साथ एक टेबल) पंक्तियां, यह लगभग 3 सेकंड में चलती है। (जॉइन विधि लंबे समय तक परिमाण का क्रम लेती है)।

नमूने में, मान लेते हैं कि उपाय स्तंभ आपको प्रतिशत रैंक की गणना कर रहे हैं, जिस पर है, और आईडी सिर्फ एक पंक्ति पहचानकर्ता (आवश्यक नहीं) है: इस के लिए

SELECT 
    id, 
    @prev := @curr as prev, 
    @curr := measure as curr, 
    @rank := IF(@prev > @curr, @[email protected], @rank) AS rank, 
    @ties := IF(@prev = @curr, @ties+1, 1) AS ties, 
    ([email protected]/@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 

क्रेडिट विधि श्लोमी नोच में जाती है। वह यहाँ विस्तार से इसके बारे में लिखते हैं:

http://code.openark.org/blog/mysql/sql-ranking-without-self-join

मैं MySQL में यह परीक्षण किया है और यह बहुत अच्छा काम करता है; ओरेकल, एसक्यूएलसेवर, आदि के बारे में कोई जानकारी नहीं

+1

यह बहुत अच्छी तरह से काम करता है। जीनियस एसक्यूएल। –

+2

दुर्भाग्य से यह उपयोगकर्ता चर के मूल्यांकन के क्रम पर निर्भर करता है, जो अपरिभाषित व्यवहार है। उस लिंक में पहली टिप्पणी MySQL मैन्युअल उद्धृत करती है: "उपयोगकर्ता चर के मूल्यांकन का क्रम अपरिभाषित है और किसी दिए गए क्वेरी में निहित तत्वों के आधार पर बदल सकता है .... सामान्य नियम किसी उपयोगकर्ता चर के लिए मान निर्दिष्ट नहीं करता है एक बयान के एक हिस्से में और उसी कथन के किसी अन्य भाग में एक ही चर का उपयोग करें। आपको परिणाम मिलने वाले परिणाम मिल सकते हैं, लेकिन इसकी गारंटी नहीं है। " संदर्भ: http://dev.mysql.com/doc/refman/5.1/en/user-variables.html – rep

1
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; 

 संबंधित मुद्दे