2013-05-08 65 views
2

我有一個數據集,它基本上由作業批次列表,每個批次中包含的作業數量以及每個作業批處理的持續時間組成。這裏是一個示例數據集:另一種百分位數方法?

CREATE TABLE test_data 
(
    batch_id NUMBER, 
    job_count NUMBER, 
    duration NUMBER 
); 

INSERT INTO test_data VALUES (1, 37, 9); 
INSERT INTO test_data VALUES (2, 47, 4); 
INSERT INTO test_data VALUES (3, 66, 6); 
INSERT INTO test_data VALUES (4, 46, 6); 
INSERT INTO test_data VALUES (5, 54, 1); 
INSERT INTO test_data VALUES (6, 35, 1); 
INSERT INTO test_data VALUES (7, 55, 9); 
INSERT INTO test_data VALUES (8, 82, 7); 
INSERT INTO test_data VALUES (9, 12, 9); 
INSERT INTO test_data VALUES (10, 52, 4); 
INSERT INTO test_data VALUES (11, 3, 9); 
INSERT INTO test_data VALUES (12, 90, 2); 

現在,我想計算持續時間字段的一些百分點。通常,這與像做了以下內容:

SELECT 
     PERCENTILE_DISC(0.75) 
      WITHIN GROUP (ORDER BY duration ASC) 
      AS third_quartile 
FROM 
     test_data; 

(其中給出的9結果)

我在這裏的問題是,我們不希望基於批拿到百分,我想讓他們基於個人工作。我可以用手很容易地通過生成運行總job_count的數字了這一點:

SELECT 
     batch_id, 
     job_count, 
     SUM(
      job_count 
     ) 
     OVER (
       ORDER BY duration 
       ROWS UNBOUNDED PRECEDING 
      ) 
      AS total_jobs, 
     duration 
FROM 
     test_data 
ORDER BY 
     duration ASC; 

BATCH_ID  JOB_COUNT TOTAL_JOBS DURATION  
6   35   35   1    
5   54   89   1    
12   90   179   2    
2   47   226   4    
10   52   278   4    
3   66   344   6    
4   46   390   6    
8   82   472   7    
9   12   484   9    
1   37   521   9    
11   3   524   9    
7   55   579   9   

因爲我有579點的工作,那麼第75百分位數將工作434綜觀上述結果集,與對應持續時間爲7,與標準功能不同。

從本質上講,我要考慮一個批處理作爲一個單獨的觀察每個作業,並基於這些百分位數,而不是在批次。

有一個比較簡單的方法來做到這一點?

+0

你的意思是你要尋找的「'每job'」時間?如果是這樣,可以使用'duration/job_count'作爲衡量標準嗎?請澄清你的要求。你的第二種方法沒有太大意義(至少在數學上)。 – 2013-05-08 22:17:13

+0

雖然正確,但仍然存在問題。 (我已經省略,爲簡單起見在模擬數據) 如果我這樣做,然後從上面的數據集所報告的第75百分位數是0.16,但所期望的第75百分位應該是0.13,因爲它是基於批次而不是仍然確定第75個百分工作。 – emiller42 2013-05-08 22:27:26

+0

另外值得注意的是,在批處理完成之前,批處理中的任何作業都將被視爲完成。所以從最終用戶的角度來看,一批中的所有工作都需要相同的時間。 – emiller42 2013-05-08 22:31:06

回答

3

我會認爲這是「加權」百分位數。我不知道在Oracle中是否有內置的分析函數,但它很容易計算。你正在那裏。

額外的想法是計算作業總數,然後用算術來選擇您想要的值。對於第75百分位數,該值是最短的持續時間,使得累計工作數量大於工作總數的0.75倍。

這裏是例如SQL:

select pcs.percentile, min(case when cumjobs >= totjobs * percentile then duration end) 
from (SELECT batch_id, job_count, 
      SUM(job_count) OVER (ORDER BY duration) as cumjobs, 
      sum(job_count) over() as totjobs, 
      duration 
     FROM test_data 
    ) t cross join 
    (select 0.25 as percentile from dual union all 
     select 0.5 from dual union all 
     select 0.75 from dual 
    ) pcs 
group by pcs.percentile; 

這個例子給你的百分位數值(並作爲額外的獎勵,對三種不同的百分位)在其自己的行每一個值。如果你想要每行的值,你需要回到原來的表格。

+0

這兩個答案都讓我確切地知道我想要什麼,但是我接受了這個答案,因爲它對較大的數據集的運行速度要快得多。(對600k批次進行測試,每批次最多可以處理1800個工作)我會同時投票,但我還不能。 謝謝你們的答案! – emiller42 2013-05-09 15:05:15

+0

爲了防止其他人對此答案中使用的表_dual_感到困惑,它是默認的Oracle系統表,常用於選擇常量(因爲SELECT語句需要FROM)。請參閱[維基百科文章](https://en.wikipedia.org/wiki/DUAL_table)。 – revengeoftheants 2015-12-09 02:33:44

0

好的。我想我有你的答案。想法是我的。實現從this Ask Tom article

SELECT PERCENTILE_DISC(0.75) 
     WITHIN GROUP (ORDER BY duration ASC) 
     AS third_quartile 
FROM(
with data as 
    (select level l 
    from dual, (select max(job_count) max_jobs from test_data) 
    connect by level <= max_jobs 
) 
    select * 
    from test_data, data 
    where l <= job_count 
    --ORDER BY duration, batch_id 
) inner 
; 

這裏是SQL Fiddle借來的。