2017-07-26 54 views
1

我正在寫一個查詢,它可以在指定範圍之間生成數字。爲給定範圍生成數字(sql查詢)

我有一個表

NUM_RANGES 

ID START_NUMBER END_NUMBER 
-- ------------ ---------- 
1    1   5 
2    6   10 

我需要得到這樣的結果:

ID NUMBER 
    -- ------ 
    1  1 
    1  2 
    1  3 
    1  4 
    1  5 
    2  6 
    2  7 
    2  8 
    2  9 
    2  10 

與此查詢我能得到正確的結果,但只適用於指定id where子句:

select id, start_number + level - 1 next_tag 
         from (select id, start_number,end_number 
         from NUM_RANGES 
         where id = 1 
     ) 
     connect by level <= end_number - start_number + 1 

沒有「where id = 1」即時通訊獲得62行重複,其中明顯的幫助,但有更大的範圍1 - 200, 200 - 500它的工作太慢..

感謝您的幫助!

+0

您的end_number需要去多高? – RBarryYoung

回答

0

在甲骨文12C可以使用CROSS APPLY:

select * 
from num_ranges 
cross apply(
    select level - 1 + start_number as my_new_number 
    from dual 
    connect by level <= end_number - start_number + 1 
); 
0

在Oracle 11.2和更早的版本,你可以使用一個分層查詢:

with 
    num_ranges (id, start_number, end_number) as (
     select 1, 1, 5 from dual union all 
     select 2, 9, 12 from dual 
    ) 
-- End of simulated input data (for testing purposes only, not part of the solution). 
-- SQL query begins below this line. 
select  id, start_number + level - 1 as nmbr 
from  num_ranges 
connect by level <= end_number - start_number + 1 
     and prior id = id 
     and prior sys_guid() is not null 
order by id, nmbr -- If needed 
; 

     ID  NMBR 
---------- ---------- 
     1   1 
     1   2 
     1   3 
     1   4 
     1   5 
     2   9 
     2   10 
     2   11 
     2   12 

具體來說,不受新行鏈接到現有的同樣的id,你正在生成一個瘋狂的不必要的行數。這就是爲什麼你需要prior id = id。需要附加條件prior sys_guid() is not null,以便Oracle不會看到不應該看到它們的循環(這是由「prior id = id」精確引起的)。

在Oracle 12.1或更高版本,可以使用lateral條款:

select n.id, l.nmbr 
from  num_ranges n, 
     lateral (select start_number + level - 1 as nmbr from dual 
        connect by level <= end_number - start_number + 1) l 
order by id, nmbr -- If needed 
; 
0

這應該工作。也很快。

with cte as (select 0 as c from dual) 
, cte4 as (select c from cte union all select c from cte union all select c from cte union all select c from cte) 
, cte256 as (select t0.c from cte4 t0, cte4 t1, cte4 t2, cte4 t3) 
, nums as (select row_number() over(order by null) as n from cte256 t0, cte256 t1, cte256 t2) 
select NR.id, nums.n as NUMBER_ 
from nums 
join NUM_RANGES NR on nums.n between NR.START_NUMBER and NR.END_NUMBER 
;