SQL

2011-08-09 10 views
13

में 2,3 क्वार्टाइल औसत की गणना करें मैं दूसरे और तीसरे क्वार्टाइल के औसत की गणना करने के लिए SQL (MySQL) में एक संग्रहित प्रो लिखना चाहता हूं।SQL

दूसरे शब्दों में मेरे पास माप के लिए रिकॉर्ड हैं कि यूआरएल लोड होने में कितना समय लगता है। रिकॉर्ड्स (आईडी, यूआरएल, समय) हैं और वे प्रत्येक यूआरएल के लिए कई मापन हैं। मैं जो करने की कोशिश कर रहा हूं वह है प्रत्येक यूआरएल के लिए निम्नतम और शीर्ष 25% (यानी निचले और ऊपरी क्वार्टाइल) को हटाएं और शेष 25% -75% लोडिंग समय की औसत गणना करें। और इसे एक और टेबल में स्टोर करें।

मैंने एमएस एसक्यूएल के लिए इसके लिए कुछ उदाहरण देखा और अपेक्षाकृत आसान लग रहा था। (चुनने के लिए ऊपर 25% कोई एनालॉग)

  • सीमा खंड percents का समर्थन नहीं करता
  • सीमा खंड अपने तर्कों का समर्थन नहीं करता चर (केवल स्थिरांक)
  • होने के लिए: लेकिन मैं MySQL का उपयोग करने के जहां है
  • कार्यों गतिशील एसक्यूएल का समर्थन नहीं करते (तैयार और निष्पादित जैसे)

और मैं जहाँ तक यहाँ मिल गया:

create procedure G(
    IN val VARCHAR(10) 
) 
Begin 
    select @cnt:=count(*) from test where a=val; 
    select @of:= @cnt /4; 
    SELECT @len:= @cnt/2; 
    Prepare stmt from 'select * from test where a="a" LIMIT ?,?'; 
    execute stmt using @of, @len; 
END; 

मैं इसे PHP में लिख सकता हूं लेकिन एसक्यूएल में सोचता हूं कि यह काफी बेहतर प्रदर्शन होगा। मैं कुछ मदद की सराहना करता हूं।

+2

जो सेल्को की 'एसक्यूएल फॉर स्मार्टज़' के पास एक अध्याय है आंकड़े (मोड, औसत, भिन्नता, आदि) यह खरीद मूल्य के लायक है। –

उत्तर

2

this question में @Richard उर्फ ​​cyberkiwi द्वारा जवाब और टिप्पणी पर देखो:

Select * 
from 
(
    SELECT tbl.*, @counter := @counter +1 counter 
    FROM (select @counter:=0) initvar, tbl 
    ORDER BY ordcolumn 
) X 
where counter >= (25/100 * @counter) and counter <= (75/100 * @counter); 
ORDER BY ordcolumn 
0

यह कैसे के बारे में?

prepare stmt from select concat('select * from test where a="a" LIMIT ',@of,@len); 
execute stmt; 
+0

1. यह अभी भी गतिशील एसक्यूएल है और मैंने 2 लिखा है कि यह लाइन अलग नहीं है। यह लाइन सिंटैक्स त्रुटि उत्पन्न करती है, भले ही यह मेरे लिए ठीक लगती है – munch

0

MySQL के साथ प्रतिशत की गणना करने के इस उत्कृष्ट उदाहरण पर नज़र डालें। मैंने इसे कुछ बड़े बड़े डेटासेट पर बड़ी सफलता के साथ उपयोग किया है। group_concat_max_len से संबंधित खंड के

http://planet.mysql.com/entry/?id=13588

लें टिप्पणी - यह वास्तव में महत्वपूर्ण है। इस मान को अधिकतम स्वीकार्य मान पर सेट करना - जो अधिकतम पैकेट आकार के लिए आपकी सेटिंग है, यह सुनिश्चित करेगा कि यदि यह स्ट्रिंग बनाता है तो बहुत बड़ा हो जाता है, तो आपको केवल 'संक्षिप्त क्षेत्र' चेतावनी के बजाय उचित त्रुटि मिल जाएगी।

SET @@group_concat_max_len := @@max_allowed_packet; 

मैं क्या करना होगा क्या इस फ़ंक्शन का उपयोग 25 वीं और 75 वीं प्रतिशतक (जो किसी एक क्वेरी में किया जा सकता) की गणना करने, और फिर डेटा के खिलाफ एक दूसरे क्वेरी चलाकर अपने शेष डेटा की औसत की गणना है ।

<?php 
$lowVal = /* result of query getting the 25%ile value */; 
$highVal = /* result of query getting the 75%ile value */; 

$strSQL = "SELECT AVG(`field`) AS myAvg 
      FROM `table` 
      WHERE { your_existing_criteria_goes_here } 
       AND `filter_field` BETWEEN '{$lowVal}' AND '{$highVal}';" 
/* Run the query and extract your data */ 
?> 

आशा सब समझ में आता है, और इस तरह से आप क्यों नहीं बस एक क्वेरी का उपयोग नहीं करते आपकी समस्या :)

+1

मुझे पता है कि यह संग्रहीत प्रक्रिया नहीं है, और PHP के भीतर किया गया है, और मुझे यकीन है कि वहां कोई व्यक्ति इसे संग्रहीत प्रक्रिया के रूप में फिर से लिख सकता है जो 25% ile और 75% ile मानों को एक ही क्वेरी से प्राप्त करने में सक्षम होता है और फिर उन्हें मुख्य फ़िल्टर किए गए क्वेरी पर लागू करता है, लेकिन उपर्युक्त यह है कि मैं कैसे करूंगा यह। इसके बाद आप अपने कोड के अन्य क्षेत्रों में 25% ile और 75% ile मानों का उपयोग कर सकते हैं, उदा। डेटा तालिका या चार्ट के लिए कुछ शीर्षलेख या किंवदंती जानकारी बनाते समय आप निर्माण कर रहे हैं;) –

0

के साथ मदद कि:

select url, avg(time) 
from mytable A 
where time > 
     (select min(B.time) + ((max(B.time)-min(B.time))/100*25) 
      from mytable B where B.url = A.url) 
and time < 
     (select max(B.time) - ((max(B.time)-min(B.time))/100*25) 
      from mytable B where B.url = A.url) 
group by url; 
+0

यह आवश्यक नहीं है कि आपको दूसरा और तीसरा क्वार्टाइल मिल जाए। यदि समय समान रूप से वितरित होते हैं तो यह करीब होगा लेकिन जैसा कि यह नहीं किया जाता है, इसके लिए क्या किया जाता है। – Dason

1

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

के मान लेते हैं, कच्चे डेटा तालिका

द्वारा बनाई गई है 0
DROP TABLE IF EXISTS `rawdata`; 
CREATE TABLE `rawdata` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `url` varchar(250) NOT NULL DEFAULT '', 
    `time` int(11) NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `time` (`time`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8; 

(और आबादी आबादी)।

यह भी मान लें चतुर्थक तालिका डेटा

DROP TABLE IF EXISTS `quartiles`; 
CREATE TABLE `quartiles` (
    `url` varchar(250) NOT NULL, 
    `Q1` float DEFAULT '0', 
    `Q2` float DEFAULT '0', 
    `Q3` float DEFAULT '0', 
    `Q4` float DEFAULT '0', 
    PRIMARY KEY (`url`), 
) ENGINE=MyISAM DEFAULT CHARSET=utf8; 

(और बाएँ खाली) द्वारा बनाई गई है करते हैं।

फिर rawdata से चतुर्थकों पॉप्युलेट करने के लिए एक प्रक्रिया की जा रही

DELIMITER ;; 

CREATE PROCEDURE `ComputeQuartiles`() 
    READS SQL DATA 
BEGIN 
    DECLARE numrows int DEFAULT 0; 
    DECLARE qrows int DEFAULT 0; 
    DECLARE rownum int DEFAULT 0; 
    DECLARE done int DEFAULT 0; 
    DECLARE currenturl VARCHAR(250) CHARACTER SET utf8; 
    DECLARE Q1,Q2,Q3,Q4 float DEFAULT 0.0; 
    DECLARE allurls CURSOR FOR SELECT DISTINCT url FROM rawdata; 
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET currenturl=''; 

    OPEN allurls; 
    FETCH allurls INTO currenturl; 
    WHILE currenturl<>'' DO 
     SELECT COUNT(*) INTO numrows FROM rawdata WHERE url=currenturl; 
     SET qrows=FLOOR(numrows/4); 
     if qrows>0 THEN 
      -- Only session parameters can be recalculated inside a query, 
      -- so @rownum:[email protected]+1 will work, but rownum:=rownum+1 will not. 
      SET @rownum=0; 
      SELECT 
       SUM(IFNULL(QA,0))/qrows, 
       SUM(IFNULL(QB,0))/qrows, 
       SUM(IFNULL(QC,0))/qrows, 
       SUM(IFNULL(QD,0))/qrows 
      FROM (
       SELECT 
        if(@rownum<qrows,time,0) AS QA, 
        if(@rownum>=qrows AND @rownum<2*qrows,time,0) AS QB, 
        -- the middle 0-3 rows are left out 
        if(@rownum>=(numrows-2*qrows) AND @rownum<(numrows-qrows),time,0) AS QC, 
        if(@rownum>=(numrows-qrows),time,0) AS QD, 
        @rownum:[email protected]+1 AS dummy 
       FROM rawdata 
       WHERE url=currenturl ORDER BY time 
      ) AS baseview 
      INTO Q1,Q2,Q3,Q4 
      ; 
      REPLACE INTO quartiles values (currenturl,Q1,Q2,Q3,Q4); 
     END IF; 

     FETCH allurls INTO currenturl; 
    END WHILE; 
    CLOSE allurls; 

END ;; 

DELIMITER ; 

मुख्य बिंदु दिखाई देगा: चक्र के लिए यूआरएल एक कर्सर

  • उपयोग करें (या नमूना अनुकूलन के रूप में URL स्वीकार करना एक पैरामीटर)
  • प्रत्येक यूआरएल के लिए पंक्तियों की कुल संख्या
  • मध्य पंक्तियों को छोड़ने के लिए कुछ मामूली गणित करें, यदि (rowcount % 4) != 0
  • URL के लिए सभी कच्चे पंक्तियों का चयन, गुणवत्ता आश्वासन-QD से एक के लिए time का मान निर्दिष्ट, पंक्ति संख्या के आधार पर, अन्य Qx मान 0
  • उपयोग एक सबक्वेरी के रूप में इस प्रश्न के एक और एक, को बताए जो सार और चतुर्थकों तालिका अद्यतन करने के लिए

मैं 18,432 कच्चे पंक्तियाँ, url=concat('http://.../',floor(rand()*10)), time=round(rand()*10000) एक 8x1.9GHz मशीन पर के साथ इस परीक्षण किया मूल्यों

  • उपयोग इस superquery के परिणाम को सामान्य और यह 0.50-0.54sec

    में लगातार समाप्त हो गया