我有一个查询按年龄组
提取一些汇总统计数据dom: '<"toolbar"><"filterPad"f>rti<"floatRight"B><"clear">',
由于各种原因,我需要输出数据为以下格式的每个1-100岁的查找表
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
...
所以我有两个问题
是否可以生成我正在寻找的t1?即一个select语句,它将创建一个
形式的t1SELECT 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
...
然后可以与具有agegroup的频率的查询结合?
答案 0 :(得分:1)
这样的东西......我包括了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.
答案 1 :(得分:1)
这是使用分层查询的不同解决方案。它不需要&#34;魔术数字&#34;此时,年龄在逻辑上由范围确定,并且没有连接(除了查询引擎在分层查询中幕后做的任何事情)。在您提供的非常小的样本上,优化器成本比我提供的基于连接的解决方案低约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
;
答案 2 :(得分:0)
如果您使用11gR2或更高版本,另一种方法是使用带有正则表达式的recursive subquery factoring来提取每个范围内的字符串值的较低和较高年龄;
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,...) - 也可以使用{{1}来完成} / substr
。
递归成员,而不是重复每个锚行,每次添加一个年龄,直到达到范围的上限数。
你也可以使用instr
,但是对于多个源行来说有点尴尬。
答案 3 :(得分:0)
问题答案:
是的,使用生成表&#34; t1&#34;的连接方法是个好主意。
生成表&#34; t1&#34;你可以使用下一个查询:
SELECT age as "Age",
CASE l_age WHEN 0 THEN 0 ELSE l_age + 1 END || '-' || r_age AS "Agegroup"
FROM (
SELECT lvl age,
CASE m5 WHEN 0 THEN (t5-1)*5 ELSE t5 *5 END l_age,
CASE m5 WHEN 0 THEN t5 *5 ELSE (t5+1)*5 END r_age
FROM (
SELECT /*+ cardinality(100) */
level lvl, mod(level, 5) m5, TRUNC(level/5) t5
FROM dual
CONNECT BY level <= 100
)
);
输出:
Age Agegroup
1 0-5
2 0-5
3 0-5
4 0-5
5 0-5
6 6-10
7 6-10
8 6-10
9 6-10
10 6-10
11 11-15
12 11-15
13 11-15
14 11-15
15 11-15
16 16-20
17 16-20
18 16-20
19 16-20
20 16-20
21 21-25
22 21-25
23 21-25
24 21-25
25 21-25
26 26-30
27 26-30
28 26-30
29 26-30
30 26-30
.........
80 76-80
81 81-85
82 81-85
83 81-85
84 81-85
85 81-85
86 86-90
87 86-90
88 86-90
89 86-90
90 86-90
91 91-95
92 91-95
93 91-95
94 91-95
95 91-95
96 96-100
97 96-100
98 96-100
99 96-100
100 96-100