甲骨文:如何在一个范围内"分组"?

Mar*_*son 31 sql oracle plsql oracle10g

如果我有这样的表格:

pkey   age
----   ---
   1     8
   2     5
   3    12
   4    12
   5    22
Run Code Online (Sandbox Code Playgroud)

我可以"分组"来计算每个年龄.

select age,count(*) n from tbl group by age;
age  n
---  -
  5  1
  8  1
 12  2
 22  1
Run Code Online (Sandbox Code Playgroud)

我可以使用什么查询按年龄范围分组?

  age  n
-----  -
 1-10  2
11-20  2
20+    1
Run Code Online (Sandbox Code Playgroud)

我在10gR2上,但我也对任何11g特定的方法感兴趣.

Ein*_*ein 57

SELECT CASE 
         WHEN age <= 10 THEN '1-10' 
         WHEN age <= 20 THEN '11-20' 
         ELSE '21+' 
       END AS age, 
       COUNT(*) AS n
FROM age
GROUP BY CASE 
           WHEN age <= 10 THEN '1-10' 
           WHEN age <= 20 THEN '11-20' 
           ELSE '21+' 
         END
Run Code Online (Sandbox Code Playgroud)

  • 不,CASE声明使用短期评估 (2认同)

Mat*_*hen 25

尝试:

select to_char(floor(age/10) * 10) || '-' 
|| to_char(ceil(age/10) * 10 - 1)) as age, 
count(*) as n from tbl group by floor(age/10);
Run Code Online (Sandbox Code Playgroud)

  • 巧妙使用楼层/分区! (4认同)
  • 这不起作用,导致**错误ORA-00979:不是GROUP BY表达式**因为GROUP BY表达式中缺少`ceil(age/10)`.但是@NitinMidha写道,这种方法的方向更好,所以我投票给这个答案. (2认同)

Win*_*ute 10

你在寻找什么,基本上是直方图的数据.

您将在x轴上具有年龄(或年龄范围),在y轴上具有计数n(或频率).

在最简单的形式中,人们可以简单地计算每个不同年龄值的数量,就像您已经描述的那样:

SELECT age, count(*)
FROM tbl
GROUP BY age
Run Code Online (Sandbox Code Playgroud)

但是,当x轴的值不同时,可能需要创建组(或簇或桶).在您的情况下,您按10的恒定范围分组.

我们可以避免WHEN ... THEN为每个范围写一行 - 如果不是关于年龄,可能会有数百个.相反,出于@NitinMidha提到的原因,@ MatthewFlaschen的方法更可取.

现在让我们构建SQL ...

首先,我们需要将年龄分成10个范围组,如下所示:

  • 0-9
  • 10-19
  • 20 - 29
  • 等等

这可以通过将age列除以10然后计算结果的FLOOR来实现:

FLOOR(age/10)
Run Code Online (Sandbox Code Playgroud)

"FLOOR返回等于或小于n的最大整数" http://docs.oracle.com/cd/E11882_01/server.112/e26088/functions067.htm#SQLRF00643

然后我们采用原始SQL并用该表达式替换age:

SELECT FLOOR(age/10), count(*)
FROM tbl
GROUP BY FLOOR(age/10)
Run Code Online (Sandbox Code Playgroud)

这没关系,但我们还看不到范围.相反,我们只看到计算的楼层值0, 1, 2 ... n.

为了获得实际的下限,我们需要将它再次乘以10,这样我们得到0, 10, 20 ... n:

FLOOR(age/10) * 10
Run Code Online (Sandbox Code Playgroud)

我们还需要每个范围的上限,即下界+ 10 - 1

FLOOR(age/10) * 10 + 10 - 1
Run Code Online (Sandbox Code Playgroud)

最后,我们将两者连接成一个这样的字符串:

TO_CHAR(FLOOR(age/10) * 10) || '-' || TO_CHAR(FLOOR(age/10) * 10 + 10 - 1)
Run Code Online (Sandbox Code Playgroud)

这创造了'0-9', '10-19', '20-29'

现在我们的SQL看起来像这样:

SELECT 
TO_CHAR(FLOOR(age/10) * 10) || ' - ' || TO_CHAR(FLOOR(age/10) * 10 + 10 - 1),
COUNT(*)
FROM tbl
GROUP BY FLOOR(age/10)
Run Code Online (Sandbox Code Playgroud)

最后,应用订单和漂亮的列别名:

SELECT 
TO_CHAR(FLOOR(age/10) * 10) || ' - ' || TO_CHAR(FLOOR(age/10) * 10 + 10 - 1) AS range,
COUNT(*) AS frequency
FROM tbl
GROUP BY FLOOR(age/10)
ORDER BY FLOOR(age/10)
Run Code Online (Sandbox Code Playgroud)

但是,在更复杂的场景中,这些范围可能不会被分组为大小为10的常量块,但需要动态聚类.Oracle包含更高级的直方图函数,请参阅http://docs.oracle.com/cd/E16655_01/server.121/e15858/tgsql_histo.htm#TGSQL366

致@MatthewFlaschen的态度; 我只解释了细节.