在 oracle 中查询范围的更好方法
Better way to query ranges in oracle
我有以下查询
SELECT 0.0, count(*) FROM tbl_a where value >= 0.0
UNION
SELECT 0.1, count(*) FROM tbl_a where value >= 0.1
UNION
SELECT 0.2, count(*) FROM tbl_a where value >= 0.2
UNION
SELECT 0.3, count(*) FROM tbl_a where value >= 0.3
UNION
SELECT 0.4, count(*) FROM tbl_a where value >= 0.4
UNION
SELECT 0.5, count(*) FROM tbl_a where value >= 0.5;
这很好用,我得到了我希望的结果,但是维护和扩展很痛苦
我试过像这样分组
SELECT
CASE
WHEN value >= 0.5 THEN 0.5
WHEN value >= 0.4 THEN 0.4
WHEN value >= 0.3 THEN 0.3
WHEN value >= 0.2 THEN 0.2
WHEN value >= 0.1 THEN 0.1
WHEN value >= 0.0 THEN 0.0
END as mag,
count(*) as numberOfCases
FROM tbl_a
GROUP BY CASE
WHEN value >= 0.5 THEN 0.5
WHEN value >= 0.4 THEN 0.4
WHEN value >= 0.3 THEN 0.3
WHEN value >= 0.2 THEN 0.2
WHEN value >= 0.1 THEN 0.1
WHEN value >= 0.0 THEN 0.0
END
ORDER BY MAG
但是结果并没有给我0值的组,也没有累积,
例如,当我声明 value >= 0
时,结果应包括所有高于或等于 0.0 的值,但它不包括仅包含 0.0
的值
你的范围是任意的吗?如果您只想将 value
舍入到最接近的十分之一,然后聚合
select round( value, 1 ),
count(*)
from table_a a
group by round( value, 1 );
不过,假设您想要任意范围,我会创建一个 range
table 或使用 CTE 模拟一个范围,具体取决于您是否要将同一组范围应用于不同的查询。
with ranges as (
select 0.1 lower_bound, 0.2 upper_bound from dual
union all
select 0.2, 0.3 from dual
union all
select 0.3, 0.4 from dual
union all
select 0.4, 0.5 from dual
union all
select 0.5, 999 from dual
)
select r.lower_bound, count(*)
from table_a a
join ranges r
on a.value >= r.lower_bound
and a.value < r.upper_bound
group by r.lower_bound
您可以将边界放入子查询中:
WITH lower_bounds (lower_bound) AS (
SELECT 0.0 FROM DUAL UNION ALL
SELECT 0.1 FROM DUAL UNION ALL
SELECT 0.2 FROM DUAL UNION ALL
SELECT 0.3 FROM DUAL UNION ALL
SELECT 0.4 FROM DUAL UNION ALL
SELECT 0.5 FROM DUAL
)
SELECT lower_bound,
COUNT(*)
FROM tbl_a
INNER JOIN lower_bounds
ON (value >= lower_bound)
GROUP BY lower_bound;
你也可以用集合来写:
SELECT b.COLUMN_VALUE AS lower_bound,
COUNT(*)
FROM tbl_a t
INNER JOIN TABLE(SYS.ODCINUMBERLIST(0.0, 0.1, 0.2, 0.3, 0.4, 0.5)) b
ON (t.value >= b.COLUMN_VALUE)
GROUP BY b.COLUMN_VALUE;
这个怎么样(定义 10 个范围起点然后连接到它们,按范围起点分组):
with ranges (s) as
( select (rownum -1) / 10 from xmltable('0 to 5') )
select r.s as range_start
, count(*)
from tbl_a t
join ranges r on t.value >= r.s
group by r.s
order by 1;
测试数据:
create table tbl_a (value) as
select dbms_random.value from xmltable('1 to 100');
您可以将基本查询结构与 window 函数结合使用:
SELECT (CASE WHEN value >= 0.5 THEN 0.5
WHEN value >= 0.4 THEN 0.4
WHEN value >= 0.3 THEN 0.3
WHEN value >= 0.2 THEN 0.2
WHEN value >= 0.1 THEN 0.1
WHEN value >= 0.0 THEN 0.0
END) as mag,
COUNT(*) as numberOfCases,
SUM(COUNT(*)) OVER (ORDER BY MIN(value)) as cumulative_numberOfCases
FROM tbl_a
GROUP BY (CASE WHEN value >= 0.5 THEN 0.5
WHEN value >= 0.4 THEN 0.4
WHEN value >= 0.3 THEN 0.3
WHEN value >= 0.2 THEN 0.2
WHEN value >= 0.1 THEN 0.1
WHEN value >= 0.0 THEN 0.0
END)
ORDER BY MAG
你也可以用这个。它利用 RANGE 窗口
条款。
with t (val) as (
select 0.0 from dual union all
select 0.0 from dual union all
select 0.1 from dual union all
select 0.1 from dual union all
select 0.1 from dual union all
select 0.2 from dual union all
select 0.2 from dual union all
select 0.2 from dual union all
select 0.2 from dual union all
select 0.3 from dual union all
select 0.3 from dual union all
select 0.3 from dual union all
select 0.4 from dual union all
select 0.4 from dual union all
select 0.4 from dual union all
select 0.4 from dual union all
select 0.4 from dual union all
select 0.5 from dual union all
select 0.5 from dual
)
select val, cnt
from (
select val
, count(*)over(order by val range between current row and unbounded following) cnt
from t
)
group by val, cnt
order by 1
;
我有以下查询
SELECT 0.0, count(*) FROM tbl_a where value >= 0.0
UNION
SELECT 0.1, count(*) FROM tbl_a where value >= 0.1
UNION
SELECT 0.2, count(*) FROM tbl_a where value >= 0.2
UNION
SELECT 0.3, count(*) FROM tbl_a where value >= 0.3
UNION
SELECT 0.4, count(*) FROM tbl_a where value >= 0.4
UNION
SELECT 0.5, count(*) FROM tbl_a where value >= 0.5;
这很好用,我得到了我希望的结果,但是维护和扩展很痛苦
我试过像这样分组
SELECT
CASE
WHEN value >= 0.5 THEN 0.5
WHEN value >= 0.4 THEN 0.4
WHEN value >= 0.3 THEN 0.3
WHEN value >= 0.2 THEN 0.2
WHEN value >= 0.1 THEN 0.1
WHEN value >= 0.0 THEN 0.0
END as mag,
count(*) as numberOfCases
FROM tbl_a
GROUP BY CASE
WHEN value >= 0.5 THEN 0.5
WHEN value >= 0.4 THEN 0.4
WHEN value >= 0.3 THEN 0.3
WHEN value >= 0.2 THEN 0.2
WHEN value >= 0.1 THEN 0.1
WHEN value >= 0.0 THEN 0.0
END
ORDER BY MAG
但是结果并没有给我0值的组,也没有累积,
例如,当我声明 value >= 0
时,结果应包括所有高于或等于 0.0 的值,但它不包括仅包含 0.0
你的范围是任意的吗?如果您只想将 value
舍入到最接近的十分之一,然后聚合
select round( value, 1 ),
count(*)
from table_a a
group by round( value, 1 );
不过,假设您想要任意范围,我会创建一个 range
table 或使用 CTE 模拟一个范围,具体取决于您是否要将同一组范围应用于不同的查询。
with ranges as (
select 0.1 lower_bound, 0.2 upper_bound from dual
union all
select 0.2, 0.3 from dual
union all
select 0.3, 0.4 from dual
union all
select 0.4, 0.5 from dual
union all
select 0.5, 999 from dual
)
select r.lower_bound, count(*)
from table_a a
join ranges r
on a.value >= r.lower_bound
and a.value < r.upper_bound
group by r.lower_bound
您可以将边界放入子查询中:
WITH lower_bounds (lower_bound) AS (
SELECT 0.0 FROM DUAL UNION ALL
SELECT 0.1 FROM DUAL UNION ALL
SELECT 0.2 FROM DUAL UNION ALL
SELECT 0.3 FROM DUAL UNION ALL
SELECT 0.4 FROM DUAL UNION ALL
SELECT 0.5 FROM DUAL
)
SELECT lower_bound,
COUNT(*)
FROM tbl_a
INNER JOIN lower_bounds
ON (value >= lower_bound)
GROUP BY lower_bound;
你也可以用集合来写:
SELECT b.COLUMN_VALUE AS lower_bound,
COUNT(*)
FROM tbl_a t
INNER JOIN TABLE(SYS.ODCINUMBERLIST(0.0, 0.1, 0.2, 0.3, 0.4, 0.5)) b
ON (t.value >= b.COLUMN_VALUE)
GROUP BY b.COLUMN_VALUE;
这个怎么样(定义 10 个范围起点然后连接到它们,按范围起点分组):
with ranges (s) as
( select (rownum -1) / 10 from xmltable('0 to 5') )
select r.s as range_start
, count(*)
from tbl_a t
join ranges r on t.value >= r.s
group by r.s
order by 1;
测试数据:
create table tbl_a (value) as
select dbms_random.value from xmltable('1 to 100');
您可以将基本查询结构与 window 函数结合使用:
SELECT (CASE WHEN value >= 0.5 THEN 0.5
WHEN value >= 0.4 THEN 0.4
WHEN value >= 0.3 THEN 0.3
WHEN value >= 0.2 THEN 0.2
WHEN value >= 0.1 THEN 0.1
WHEN value >= 0.0 THEN 0.0
END) as mag,
COUNT(*) as numberOfCases,
SUM(COUNT(*)) OVER (ORDER BY MIN(value)) as cumulative_numberOfCases
FROM tbl_a
GROUP BY (CASE WHEN value >= 0.5 THEN 0.5
WHEN value >= 0.4 THEN 0.4
WHEN value >= 0.3 THEN 0.3
WHEN value >= 0.2 THEN 0.2
WHEN value >= 0.1 THEN 0.1
WHEN value >= 0.0 THEN 0.0
END)
ORDER BY MAG
你也可以用这个。它利用 RANGE 窗口 条款。
with t (val) as (
select 0.0 from dual union all
select 0.0 from dual union all
select 0.1 from dual union all
select 0.1 from dual union all
select 0.1 from dual union all
select 0.2 from dual union all
select 0.2 from dual union all
select 0.2 from dual union all
select 0.2 from dual union all
select 0.3 from dual union all
select 0.3 from dual union all
select 0.3 from dual union all
select 0.4 from dual union all
select 0.4 from dual union all
select 0.4 from dual union all
select 0.4 from dual union all
select 0.4 from dual union all
select 0.5 from dual union all
select 0.5 from dual
)
select val, cnt
from (
select val
, count(*)over(order by val range between current row and unbounded following) cnt
from t
)
group by val, cnt
order by 1
;