Oracle SQL select语句为查找表生成数字1-100?

时间:2016-08-08 17:40:20

标签: sql oracle

我有一个查询按年龄组

提取一些汇总统计数据
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
...

所以我有两个问题

  1. 这是一种有意义的方法吗?
  2. 是否可以生成我正在寻找的t1?即一个select语句,它将创建一个

    形式的t1
    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
    

    ...

  3. 然后可以与具有agegroup的频率的查询结合?

4 个答案:

答案 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)

问题答案:

  1. 是的,使用生成表&#34; t1&#34;的连接方法是个好主意。

  2. 生成表&#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
     )
    );
    
  3. 输出:

                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