2013-05-08 56 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借来的。