为查找表生成数字1-100的Oracle SQL select语句?
我有一个查询,按年龄组提取一些聚合统计数据为查找表生成数字1-100的Oracle SQL select语句?,sql,oracle,Sql,Oracle,我有一个查询,按年龄组提取一些聚合统计数据 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
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
所以我有两个问题
这是一种有意义的方法吗?
有可能生成我要找的t1吗?也就是说,一个select语句将创建表单的t1
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
然后可以将其与具有按年龄组划分的频率的查询结合起来?如果您使用的是11gR2或更高版本,另一种方法是使用正则表达式从字符串值中提取每个范围内的上下年龄
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,但使用多个源行会有点麻烦。如果您使用的是11gR2或更高版本,另一种方法是使用正则表达式从字符串值中提取每个范围内的上下限年龄
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,但使用多个源行时会有点麻烦。类似这样的功能。。。我包括了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
;
像这样的。。。我包括了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
;
这里有一个不同的解决方案,使用分层查询。它不再需要神奇的数字,年龄在逻辑上由范围决定,除了在分层查询中查询引擎在后台执行的任何操作之外,没有连接。在您提供的非常小的示例中,优化器的成本比我提供的基于连接的解决方案低约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
;
这里有一个不同的解决方案,使用分层查询。它不再需要神奇的数字,年龄在逻辑上由范围决定,除了在分层查询中查询引擎在后台执行的任何操作之外,没有连接。在您提供的非常小的示例中,优化器的成本比我提供的基于连接的解决方案低约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
;
有关问题的答复:
是的,对生成的表t1使用连接方法是个好主意
要生成表t1,可以使用下一个查询:
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
)
);
有关问题的答复:
是的,对生成的表t1使用连接方法是个好主意
要生成表t1,可以使用下一个查询:
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
)
);
这将生成数字1-100:选择rownum
由于dual connect by level中的n,示例输出的可能副本的年龄不为0,这是故意的吗?如果包括零,除第一年外,是否所有范围均为5年?是否可以改为修改原始查询?例如,也许可以使用分析函数一次性完成。@TonyAndrews,谢谢,这正是我要找的。这将生成数字1-100:按级别从dual connect中选择rownum作为n示例输出的可能副本没有0岁,这是故意的吗?如果包括零,除第一年外,是否所有范围均为5年?还有,是否可以改为修改原始查询?例如,也许可以用分析函数一次性完成。@TonyAndrews谢谢,这正是我想要的。这就是我所指的,但非常模糊*8-我倾向于使用递归CTE而不是强制使用非determistic prior子句,但是在这样一个小的数据集上,这可能会更好。@AlexPoole-一般来说,我也更喜欢递归CTE;我对拆分大型CSV所做的一些不完全正式的测试似乎表明递归查询比分层查询快得多。分层查询的一个好处是,它们可以用于11.2之前的版本。是的,我也要提到这一点。这就是我所指的,但非常模糊*8-我倾向于使用递归CTE,而不是强制使用非detrmistic previor子句,但在这样一个小的数据集上可能会更好。@AlexPoole-我也更喜欢递归CTE,一般来说我对拆分大型CSV所做的一些不完全正式的测试似乎表明递归查询比分层查询快得多。分层查询的一个好处是,它们可以用于11.2之前的版本。是的,我也要提到这一点。