2017-07-04 79 views
-1

我試圖找到一個解決方案,沒有運氣。Percentile_disc()非循環值

在我的查詢中,即時選擇count(*)percentile_disc(.9)找到這個的第90個位置。 情況是,當計數爲29時,第90百分位數比第27位數接近於27,但仍返回第27個對象。

有什麼辦法可以說,如果5 <第< 10減1的結果?

表參考

ID Count 90th 
------------------- 
1  50  45 
2  40  36 
3  27  25  <-- Should be 24 
4  9  9  <-- Should be 8 

90%的9爲0.9,它應該刪除1和所得8.

---直到這是我的第N個百分位數的理解---

現在我所擁有的:

我的表有一些條目(每天+ 100k),所以我想每天運行這個查詢。

Service_id start_time  end_time 
------------------------------------- 
Service1 1499025651614 1499025651648 
Service2 1499025655145 1499025655434 
Service3 1499025656029 1499025656112 
Service2 1499025658755 1499025659135 
Service3 1499025726862 1499025728346 
Service1 1499025748782 1499025750032 
Service3 1499025749277 1499025749900 
Service3 1499025757681 1499025758517 
Service2 1499025775000 1499025775101 
Service1 1499025785556 1499025785633 
... 

我有一個查詢,選擇最小,最大和平均爲每個服務

select mt.SERVICE_ID as SERVICE_ID, 
      count(*) as COUNT, 
      round(avg((mt.end_time - mt.start_time)/1000), 2) as Avg, 
      round(min((mt.end_time - mt.start_time)/1000), 2) AS Min, 
      round(max((mt.end_time - mt.start_time)/1000), 2) AS Max 
     from myTable mt 
    group by mt.service_id 

我想結合使用連接之前discused 90個百分點。

select service_id, round(percentile_disc(.90) within group(order by elapsed), 2) as perc 
from (select mt.service_id, ((mt.end_time - mt.start_time)/1000) as elapsed 
     from myTable mt) 
group by service_id 

問題來當計數(可以說)9,在這種情況下,MAXPerc是相同的(由於百分沒有刪除任何東西),但我需要在這個特殊的情況下,刪除最後一個,給我的結果8號位置的調整。

在這種情況下,有任何方法可以刪除一個位置?

+0

請提供[MCVE ]包括您的表的DDL語句,DML語句(例如說明您的問題和您的預期輸出的示例數據)(詳細描述預期輸出的邏輯)。目前,您問題中的文字描述與「參考表格」不匹配,也不符合您的查詢,因此尚不清楚您嘗試實現的內容。 – MT0

+0

@MT0增加了更多數據,希望對澄清已經足夠了。謝謝 –

回答

0

PERCENTILE_DISC()並不完全符合您的想法。

Oracle Documentation

目的

PERCENTILE_DISC是假設一個離散分佈模型的逆分佈函數。它採用百分位值和排序規範,並返回集合中的元素。計算中忽略空值。

...

對於給定的百分位值PPERCENTILE_DISC排序在ORDER表達式的值BY子句,並返回具有最小CUME_DIST值的值(相對於相同的排序規範),其是大於或等於P

解析例

下面的示例計算在樣品表每個小時僱員的工資的中值離散的百分。員工:

SELECT last_name, salary, department_id, 
    PERCENTILE_DISC(0.5) WITHIN GROUP (ORDER BY salary DESC) 
     OVER (PARTITION BY department_id) "Percentile_Disc", 
    CUME_DIST() OVER (PARTITION BY department_id 
     ORDER BY salary DESC) "Cume_Dist" 
FROM employees where department_id in (30, 60); 

LAST_NAME   SALARY DEPARTMENT_ID Percentile_Disc Cume_Dist 
------------- ---------- ------------- --------------- ---------- 
Raphaely   11000   30   2900 .166666667 
Khoo    3100   30   2900 .333333333 
Baida    2900   30   2900   .5 
Tobias    2800   30   2900 .666666667 
Himuro    2600   30   2900 .833333333 
Colmenares   2500   30   2900   1 
Hunold    9000   60   4800   .2 
Ernst    6000   60   4800   .4 
Austin    4800   60   4800   .8 
Pataballa   4800   60   4800   .8 
Lorentz    4200   60   4800   1 

的中值用於系30是2900,這是其 相應百分值(CUME_DIST)的最小值大於 或等於0.5。部門60的中間值是4800, ,這是相應百分位數值大於或等於0.5的最小值。

在他們的文檔中了,如果百分位設置爲0.9(而不是0.5)的例子,你可以看到CUME_DIST去從0.81(用於部門60),所以PERCENTILE_DISC(0.9) ...會給45510764714​​自這是具有最小的CUME_DIST大於或等於0.9的值。要獲得倒數第二個值,在這種情況下,您需要百分之0.8

問題來當計數(可以說)9,在這種情況下,MAX和PERC是相同的(由於百分沒有刪除任何東西),但我需要在這個特殊的情況下,刪除最後一個,給我的結果是8號位的時機。

爲9項,每行的CUME_DIST值將是:

ROW_NUMBER CUME_DIST 
---------- --------- 
     1  .111 
     2  .222 
     3  .333 
     4  .444 
     5  .556 
     6  .667 
     7  .778 
     8  .889 
     9  1.000 

如果使用PERCENTILE_DISC(0.9)那麼它會尋找具有大於或等於該數值的最低CUME_DIST價值 - 只有一個值1.000,這也是最大值。

如果你想要一個不同的值,那麼你需要使用更低的百分位數。

更新

你可以嘗試這樣的事情:

select service_id, 
     elapsed as perc 
from (
    select service_id, 
     (end_time - start_time)/1000 as elapsed, 
     ROW_NUMBER() OVER (PARTITION BY service_id ORDER BY (end_time - start_time)) 
      AS rn, 
     COUNT() OVER (PARTITION BY service_id) AS ct 
    from myTable 
) 
WHERE rn = ROUND(0.9 * ct); 

更改的最後一行用ROUNDFLOORCEIL適用於您的業務邏輯。如果我已正確確定邏輯,CEIL將給出與使用PERCENTILE_DISC相同的答案。

我需要的是計數爲7,刪除最後一條記錄並返回第6個值(7的90%爲0.7,舍入爲1),計數爲21,刪除最後2條記錄並返回第19個位置值(21的90%爲2.1到2),依此類推。

使用rn = ROUND(0.9 * ct)

  • 如果計數爲7,則0.9 * 7 = 6.3所以ROUND(6.3)會給第6行
  • 如果計數爲21,然後0.9 * 21 = 18.9所以ROUND(18.9)將給予19排
  • 如果計數是3然後0.9 * 3 = 2.7所以ROUND(2.7)會給第3行(最大值)。

你所期望的要返回的小套目前尚不清楚 - 如果你從來不去最大行(除非只有一個行),然後是這樣的:

WHERE rn = GREATEST(1, LEAST(ct - 1, ROUND(0.9 * ct))) 
+0

那麼,在這種情況下,我應該使用什麼? –

+0

如果組中有9行,並且需要第8個值,則使用'8/9 = 0.888 ...'(或任何大於'7/9'且小於或等於'8/9'的值) 。 – MT0

+0

有什麼辦法可以自動化這個嗎?在DB中有超過150種不同的服務,有些被稱爲2次,有些被稱爲+2000次。我需要的是計數爲7,刪除最後一條記錄並返回第6個值(7的90%爲0.7,循環爲1),計數爲21,刪除最後2條記錄並返回第19個位置值( 21的90%是2.1到2)等等。感謝您的時間 –