我有一个查询,它按年龄组提取一些汇总的统计数据。
Agegroup Freq
0-5 2.3
6-10 3.2
11-15 3.6
由于各种原因,我需要输出数据作为以下格式中每一个年龄1-100岁的查找表
Age Agegroup Freq
1 0-5 2.3
2 0-5 2.3
3 0-5 2.3
4 0-5 2.3
5 0-5 2.3
6 6-10 3.2
7 6-10 3.2
8 6-10 3.2
9 6-10 3.2
10 6-10 3.2
...
我怎么能继续这么做?我无法创建表,所以我在想,是否有一种方法可以编写一种select语句,该语句包含所有的年龄1-100岁和年龄组,然后将其加入到原始查询中,该查询具有按年龄组计算的频率--如下所示
SELECT t1.age, [case when statemenet that assigns the correct age group from t1.Age] "Agegroup"
FROM ([statemement that generates numbers 1-100] "age") t1
JOIN (Original query that creates the aggreated agegroup data) t2 on t1.Agegroup = t2.Agegroup
所以我有两个问题
它可以与按年龄组划分频率的查询相结合吗?
发布于 2016-08-08 18:20:45
就像这样..。我包括了0岁(如果需要的话可以排除它),我只读了15岁。这是硬编码的;只要做一点额外的工作,它就可以匹配范围内最高的年龄。
这个版本做了不必要的工作,因为它反复计算子字符串。它仍然可以在不到一秒钟的时间内执行,但是如果性能变得重要,就可以首先编写它来计算CTE中的那些子字符串,这样就不会重复计算它们。(此处未显示)
with
inputs (agegroup, freq ) as (
select '0-5', 2.3 from dual union all
select '6-10', 3.2 from dual union all
select '11-15', 3.6 from dual
)
select c.age, i.agegroup, i.freq
from (select level - 1 as age from dual connect by level <= 16) c
inner join inputs i
on age between to_number(substr(i.agegroup, 1, instr(i.agegroup, '-') - 1))
and to_number(substr(i.agegroup, instr(i.agegroup, '-') + 1))
order by age
;
输出:
AGE AGEGROUP FREQ
---- --------- ----------
0 0-5 2.3
1 0-5 2.3
2 0-5 2.3
3 0-5 2.3
4 0-5 2.3
5 0-5 2.3
6 6-10 3.2
7 6-10 3.2
8 6-10 3.2
9 6-10 3.2
10 6-10 3.2
11 11-15 3.6
12 11-15 3.6
13 11-15 3.6
14 11-15 3.6
15 11-15 3.6
16 rows selected.
发布于 2016-08-08 19:42:03
这里有一个不同的解决方案,使用分层查询。它不再需要“魔术数字”了,年龄是由范围逻辑决定的,并且没有连接(除了查询引擎在层次化查询的幕后所做的其他事情)。在您提供的非常小的示例中,优化器成本比我提供的基于连接的解决方案低20%,这可能会导致执行速度稍微快一些。
(注:我发布了两种不同的解决方案,因此我认为它们是不同的答案-而不是编辑我之前的文章。我不知道哪一种行动合适。)
还有一条要承认@AlexPoole在他的帖子中提到了这种方法;我直到现在才看到它,否则我会从一开始就承认它。
with
inputs (agegroup, freq ) as (
select '0-5', 2.3 from dual union all
select '6-10', 3.2 from dual union all
select '11-15', 3.6 from dual
)
select to_number(substr(agegroup, 1, instr(agegroup, '-') - 1)) + level - 1 as age,
agegroup, freq
from inputs
connect by level <= 1 + to_number(substr(agegroup, instr(agegroup, '-') + 1)) -
to_number(substr(agegroup, 1, instr(agegroup, '-') - 1))
and prior agegroup = agegroup
and prior sys_guid() is not null
order by age
;
发布于 2016-08-08 18:16:04
如果使用11 gR2或更高版本,另一种方法是使用带有正则表达式的递归子查询分解从字符串值中提取每个范围内的较低和较高年龄;
with original_query (agegroup, freq) as (
-- Original query that creates the aggreated agegroup data
select '0-5', 2.3 from dual
union all select '6-10', 3.2 from dual
union all select '11-15', 3.6 from dual
),
r (age, agegroup, freq) as (
select to_number(regexp_substr(agegroup, '\d+', 1, 1)), agegroup, freq
from original_query
union all
select age + 1, agegroup, freq
from r
where age < to_number(regexp_substr(agegroup, '\d+', 1, 2))
)
select age, agegroup, freq
from r
order by age;
AGE AGEGR FREQ
---------- ----- ----------
0 0-5 2.3
1 0-5 2.3
2 0-5 2.3
3 0-5 2.3
4 0-5 2.3
5 0-5 2.3
6 6-10 3.2
7 6-10 3.2
8 6-10 3.2
9 6-10 3.2
10 6-10 3.2
11 11-15 3.6
12 11-15 3.6
13 11-15 3.6
14 11-15 3.6
15 11-15 3.6
锚成员从现有的结果集中获取每个原始行,并提取下限数字(0、6、11、.)使用一个简单的正则表达式--这也可以用substr
/instr
来完成。
递归成员会重复这些锚定行中的每一行,每次增加一行,直到达到范围的上限数为止。
您也可以使用connect by
,但是对于多个源行,它会更尴尬一些。
https://stackoverflow.com/questions/38835399
复制相似问题