我试图找到一个没有运气的解决方案。
在我的查询中,我选择count(*)
和percentile_disc(.9)
来找到第90个位置。
案例是,当计数为29时,第90个百分位数比第27个百分位数更接近26但仍然返回第27个目标。
有任何方式可以说,如果5< Nth< 10将结果减少一个?
参考表
ID Count 90th
-------------------
1 50 45
2 40 36
3 27 25 <-- Should be 24
4 9 9 <-- Should be 8
9的90%是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
我希望在使用联接之前纳入第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时出现问题,在这种情况下,MAX
和Perc
是相同的(由于百分位数没有删除任何东西),但我需要这个特殊情况,删除最后一个,给我作为结果在第8位的调整。
在这种情况下,还有什么方法可以删除一个位置吗?
答案 0 :(得分:0)
PERCENTILE_DISC()
并不能完全按照您的想法行事。
<强>目的强>
PERCENTILE_DISC是一个逆分布函数,它假设一个离散分布模型。它需要百分位值和排序规范,并从集合中返回一个元素。在计算中忽略空值。
...
对于给定的百分位值
P
,PERCENTILE_DISC
对ORDER BY子句中的表达式值进行排序,并返回值CUME_DIST
最小的值(相对于同一种类)规范)大于或等于P
。分析示例
以下示例计算样本表hr.employees中每位员工薪水的中位数离散百分位数:
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.8
到1
(对于部门60),PERCENTILE_DISC(0.9) ...
会给4200
,因为这是最小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 );
根据您的业务逻辑,将最后一行更改为使用ROUND
,FLOOR
或CEIL
。如果我已正确确定逻辑,CEIL
将给出与使用PERCENTILE_DISC
相同的答案。
我需要的是计数是7,删除最后一条记录并返回第6个值(7的90%是0.7,舍入为1),计数是21,删除最后2条记录并返回第19个位置-value(21的90%是2.1轮到2)依此类推。
使用rn = ROUND( 0.9 * ct )
:
0.9 * 7 = 6.3
所以ROUND( 6.3 )
会给出第6行0.9 * 21 = 18.9
,ROUND( 18.9 )
将给出第19行0.9 * 3 = 2.7
,ROUND( 2.7 )
将给出第3行(最大值)。目前还不清楚你希望小集返回什么 - 如果你不想要最大行(除了只有一行),那么就像:
WHERE rn = GREATEST( 1, LEAST( ct - 1, ROUND( 0.9 * ct ) ) )