2016-08-08 1 views
0

私は、様々な理由から年齢グループルックアップ・テーブルの1〜100の数値を生成するOracle SQLのselect文はありますか?

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〜100歳の年齢の選択文を作成し、計算された頻度を持つ元のクエリに結合する方法があると思っていますagegroup - この

のようなもの
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 

だから私は二つの質問

  1. を持っているが、これは全く理にかなったアプローチですか?
  2. 私は探しているt1を生成することは可能ですか?私。その後、agegroupによって周波数を持つクエリで結合することができ、フォーム

    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 
    

    のT1を作成するselect文...

+2

これは番号1-100を生成します: 'デュアルからnとROWNUMの選択接続レベル<= 100; ' –

+3

[1から100までの数字のリストを生成するためのSQLの重複]可能性があります(http://stackoverflow.com/questions/2847226/sql-to-generate-a-list-of- 1から100までの数字) – sstan

+0

あなたのexa mple出力には年齢0がありませんが、それは意図的ですか?すべての範囲は5年です(ゼロが含まれる場合、最初の範囲を除く)?代わりに元のクエリを変更することも可能です。たとえば、これは、解析機能を使用して一度に行うことができます。 –

答えて

0

11g2以上の場合は、正規表現で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、...)を抽出する - にも用いて行うことができることsubstr/instr

再帰メンバは、アンカー行のそれぞれを繰り返して、範囲の上限数に達するまで毎回1を加算します。

connect byも使用できますが、複数のソース行ではもう少し扱いに​​くいです。

1

このようなもの...私は年齢0(必要な場合は除外することができます)を含め、私は15歳までしか過ごしませんでした。少し余分な作業で、範囲内の最高年齢に合わせることができます。

このバージョンでは、部分文字列が繰り返し計算されるため、このバージョンでは不要な作業が行われます。これは1秒未満で実行される可能性がありますが、パフォーマンスが重要になった場合、最初に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

は、階層問合せを使用して、別のソリューションです。それはもはや "マジックナンバー"を必要とせず、年齢は論理的に範囲によって決定され、結合はありません(クエリエンジンが階層クエリの中で何をしているかを除いて)。あなたが提供した非常に小さなサンプルでは、​​オプティマイザ・コストは、私が提供したジョイン・ベースのソリューションよりも約20%少なくなり、実行速度が少し向上します。

(NOTE - 。私はこれらが別々の回答していると考えているので、私は2つの異なる解決策を掲載 - 。私の以前の記事を編集するとは対照的に、私はアクションが適切であるかわからなかった)

はまた別のノートがそれを認めること@ 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 
; 
+0

これは、私が言及したものですが、非常に曖昧です。* 8-)私は、非detrmisticの前の節を強制するよりも再帰的なCTEを好む傾向がありますが、このような小さなデータセットではより良いかもしれません。 –

+1

@AlexPoole - 一般的に再帰的なCTEも好きです。私が大規模なCSVを分割して行った(完全に正式ではない)テストでは、再帰的なクエリが階層的なクエリよりもかなり速いことが示唆されたようです。階層型の利点の1つは、11.2より前のバージョンで使用できることです。 – mathguy

+0

はい、それも言及することを意味する。 –

0

回答:

  1. はい、生成されたテーブル "T1" とアプローチに参加使用することは良いアイデアです。

  2. テーブルを生成するには、 "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 
    ) 
    ); 
    

出力:

  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 
関連する問題