2013-05-08 2 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_count' в качестве меры? Просьба уточнить ваши требования. Ваш второй подход не имеет большого смысла (по крайней мере, математически). –

+0

Хотя это верно, это все еще оставляет проблему на месте. (Я просто пропустил это для простоты в макетных данных) Если я это сделаю, то указанный 75-й процентиль из вышеуказанного набора данных равен 0,16, но желаемый 75-й процентиль должен быть 0,13, потому что он все еще определяет 75-й процентили на основе партий, а не рабочие места. – emiller42

+0

Также стоит отметить, что функционально, никакая работа в партии не считается законченной, пока вся партия не будет закончена. Таким образом, с точки зрения конечного пользователя все задания в пакете занимают одинаковое количество времени. – emiller42

ответ

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

Оба этих ответа дают мне то, что я хочу, но я принимаю это, поскольку он работает намного быстрее против большего набора данных.(Протестировано против 600 тыс. Партий, до 1800 рабочих мест за партию). Я бы обогнал обоих, но пока не могу. Благодарим вас обоих за ответы! – emiller42

+0

На всякий случай, когда кто-то путается с таблицей _dual_, используемой в этом ответе, это системная таблица Oracle по умолчанию, часто используемая для выбора констант (потому что для инструкции SELECT требуется FROM). См. Статью [Wikipedia] (https://en.wikipedia.org/wiki/DUAL_table). – revengeoftheants

0

OK. Думаю, у меня есть ваш ответ. Идея моя. Реализация заимствовано из 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.

 Смежные вопросы

  • Нет связанных вопросов^_^