在oracle 11gr2中创建百分比范围的更好方法

时间:2014-10-21 17:20:19

标签: oracle oracle11g group-by percentage

我有一张像

这样的表格
Value    Average    Difference%
1        2          50
5.5      13         43
3        10         30

我想把它变成类似

的东西
Difference Range   #
 0-30              1
41-50              2

稍后将其绘制成类似直方图的图形。

在我写完典型case when difference < 10 then 'under 10%' else when ... end之后,我开始想知道是否有更好的方法来做到这一点。找到PERCENT_RANK,这似乎就是这样,但不是我想要的。

如果愤怒的步骤得到修复会更好,例如每个5%:

case
  when dif_perc_med = 0 then 'Ok' 
  when dif_perc_med < 0.05 then 'até 5%' 
  when dif_perc_med < 0.1 then 'até 10%' 
  when dif_perc_med < 0.15 then 'até 15%' 
  when dif_perc_med < 0.2 then 'até 20%' 
  when dif_perc_med < 0.25 then 'até 25%' 
  when dif_perc_med < 0.3 then 'até 30%' 
  when dif_perc_med < 0.35 then 'até 35%' 
  when dif_perc_med < 0.4 then 'até 40%'
  when dif_perc_med < 0.45 then 'até 45%' 
  when dif_perc_med < 0.5 then 'até 50%' 
  when dif_perc_med < 0.55 then 'até 55%' 
  when dif_perc_med < 0.6 then 'até 60%' 
  when dif_perc_med < 0.65 then 'até 65%' 
  when dif_perc_med < 0.7 then 'até 70%' 
  when dif_perc_med < 0.75 then 'até 75%' 
  when dif_perc_med < 0.8 then 'até 80%' 
  when dif_perc_med < 0.85 then 'até 85%' 
  when dif_perc_med < 0.9 then 'até 90%' 
  when dif_perc_med < 0.95 then 'até 95%'
else 'mais de 95%'end as rng_perc_dif

有什么想法吗?

1 个答案:

答案 0 :(得分:1)

你可以使用简单的算术来做到这一点:

SELECT TRUNC("Difference"/5) "Rank", COUNT("Difference")
FROM T
GROUP BY TRUNC("Difference"/5);

如果您需要所有值(包括&#34;缺少&#34;那些),您可以在某个生成的表上使用连接:

SELECT ("Rank")*5 "From", ("Rank"+1)*5 "To", NVL(V."Cnt", 0) "Cnt" 
--           from N           to N+1
FROM (
  SELECT LEVEL-1 "Rank" FROM DUAL CONNECT BY LEVEL <= 100/5
  --          ^^
  --    start from zero
) C
LEFT JOIN (
    SELECT TRUNC("Difference"/5) "Rank", COUNT("Difference") "Cnt"
    FROM T
    GROUP BY TRUNC("Difference"/5)
) V
USING("Rank")
ORDER BY "Rank"

在这个示例中,我已经对所有5进行了硬编码 - 对于生产代码,您很可能将它们转换为参数。


10g 开始(我认为)Oracle确实支持WIDTH_BUCKET函数,该函数执行与上述算术大致相同的工作。所以你可以这样重写那个查询:

SELECT ("Rank"-1)*5 "From", ("Rank")*5 "To", COUNT(V.ROWID) "Cnt"
--           from N-1           to N
FROM (
  SELECT LEVEL "Rank" FROM DUAL CONNECT BY LEVEL <= 100/5
  --        ^^
  --    start from one
) C
LEFT JOIN (
    SELECT WIDTH_BUCKET("Difference",0,100,20) "Rank"
    FROM T
) V
USING("Rank")
GROUP BY "Rank"
ORDER BY "Rank";

请参阅http://sqlfiddle.com/#!4/d7398/29了解各种解决方案的实时测试