Oracle求值的連續範圍

Oracle求值的連續範圍

 

         首先帶上原文的鏈接http://www.itpub.net/thread-1873736-1-1.html

         有數據如下

        

Sql代碼  
  1. with tmp_t as(  select  1 as id ,'aaa' as v_name from dual union all  
  2.         select  2 as id ,'aaa' as v_name from dual union all  
  3.         select  3 as id ,'aaa' as v_name from dual union all  
  4.         select  5 as id ,'aaa' as v_name from dual union all  
  5.         select  6 as id ,'bbb' as v_name from dual union all  
  6.         select  7 as id ,'bbb' as v_name from dual union all  
  7.         select  8 as id ,'ccc' as v_name from dual union all  
  8.         select  9 as id ,'zzz' as v_name from dual union all  
  9.         select 11 as id ,'zzz' as v_name from dual union all  
  10.         select 13 as id ,'zzz' as v_name from dual union all  
  11.         select 14 as id ,'zzz' as v_name from dual )   
with tmp_t as(  select  1 as id ,'aaa' as v_name from dual union all
        select  2 as id ,'aaa' as v_name from dual union all
        select  3 as id ,'aaa' as v_name from dual union all
        select  5 as id ,'aaa' as v_name from dual union all
        select  6 as id ,'bbb' as v_name from dual union all
        select  7 as id ,'bbb' as v_name from dual union all
        select  8 as id ,'ccc' as v_name from dual union all
        select  9 as id ,'zzz' as v_name from dual union all
        select 11 as id ,'zzz' as v_name from dual union all
        select 13 as id ,'zzz' as v_name from dual union all
        select 14 as id ,'zzz' as v_name from dual ) 

   

      求v_name的連續區間

      期望的結果

     

       容易理解的寫法:

      

Sql代碼  
  1. select v_name,   
  2.        decode(count(*), 1, to_char(min(id)), min(id) || '-' || max(id)) b   
  3.   from (select id, v_name, max(rn) over(partition by v_name order by id) rn   
  4.           from (select id,   
  5.                        v_name,   
  6.                        decode(id - lag(id)   
  7.                               over(partition by v_name order by id),   
  8.                               1,   
  9.                               0,   
  10.                               id) rn   
  11.                   from tmp_t))   
  12.  group by v_name, rn   
  13.  order by v_name, rn;  
select v_name,
       decode(count(*), 1, to_char(min(id)), min(id) || '-' || max(id)) b
  from (select id, v_name, max(rn) over(partition by v_name order by id) rn
          from (select id,
                       v_name,
                       decode(id - lag(id)
                              over(partition by v_name order by id),
                              1,
                              0,
                              id) rn
                  from tmp_t))
 group by v_name, rn
 order by v_name, rn;

 

    簡單的寫法

   

Sql代碼  
  1. select v_name,   
  2.        decode(to_char(mi),to_char(ma) ,to_char(ma),to_char(mi) || '-' || to_char(ma)) b   
  3.   from (select v_name, min(id) mi, max(id) ma   
  4.           from (select t.* from tmp_t t order by t.v_name, t.id)   
  5.          group by v_name, id - rownum   
  6.          order by v_name);  
select v_name,
       decode(to_char(mi),to_char(ma) ,to_char(ma),to_char(mi) || '-' || to_char(ma)) b
  from (select v_name, min(id) mi, max(id) ma
          from (select t.* from tmp_t t order by t.v_name, t.id)
         group by v_name, id - rownum
         order by v_name);

    簡潔的寫法

   

Sql代碼  
  1. --連續ID減行號的差值一定是相同的   
  2. select v_name,   
  3.        decode(count(*), 1, to_char(min(id)), min(id) || '-' || max(id)) b   
  4.   from (select t.*, id - row_number() over(partition by v_name order by id) gp   
  5.           from tmp_t t)   
  6.  group by v_name, gp   
  7.  order by v_name  
--連續ID減行號的差值一定是相同的
select v_name,
       decode(count(*), 1, to_char(min(id)), min(id) || '-' || max(id)) b
  from (select t.*, id - row_number() over(partition by v_name order by id) gp
          from tmp_t t)
 group by v_name, gp
 order by v_name

    求連續值範圍一般都是先求差值,在按差值分組,如下所示:

   

Sql代碼  
  1. with tmp_t as(   
  2. select to_date('201401','yyyy-mm'as v_month,100  as v_value from dual union all  
  3. select to_date('201402','yyyy-mm'),100 from dual union all  
  4. select to_date('201404','yyyy-mm'),100 from dual union all  
  5. select to_date('201405','yyyy-mm'),300 from dual union all  
  6. select to_date('201406','yyyy-mm'),100 from dual union all  
  7. select to_date('201311','yyyy-mm'),110 from dual union all  
  8. select to_date('201310','yyyy-mm'),110 from dual union all  
  9. select to_date('201407','yyyy-mm'),100 from dual )   
  10. select v_value,decode(to_char(min(v_month), 'yyyymm'),   
  11.               to_char(max(v_month), 'yyyymm'),   
  12.               to_char(max(v_month), 'yyyymm'),   
  13.               to_char(min(v_month), 'yyyymm') || '-' ||   
  14.               to_char(max(v_month), 'yyyymm')) v_range   
  15.   from (select v_month,   
  16.                v_value,   
  17.                to_number(to_char(add_months(v_month,   
  18.                                             -1 * row_number()   
  19.                                             over(partition by v_value order by  
  20.                                                  v_month)),   
  21.                                  'yyyymm')) diff   
  22.           from tmp_t)   
  23.  group by diff, v_value   
  24.  order by 1;  
with tmp_t as(
select to_date('201401','yyyy-mm') as v_month,100  as v_value from dual union all
select to_date('201402','yyyy-mm'),100 from dual union all
select to_date('201404','yyyy-mm'),100 from dual union all
select to_date('201405','yyyy-mm'),300 from dual union all
select to_date('201406','yyyy-mm'),100 from dual union all
select to_date('201311','yyyy-mm'),110 from dual union all
select to_date('201310','yyyy-mm'),110 from dual union all
select to_date('201407','yyyy-mm'),100 from dual )
select v_value,decode(to_char(min(v_month), 'yyyymm'),
              to_char(max(v_month), 'yyyymm'),
              to_char(max(v_month), 'yyyymm'),
              to_char(min(v_month), 'yyyymm') || '-' ||
              to_char(max(v_month), 'yyyymm')) v_range
  from (select v_month,
               v_value,
               to_number(to_char(add_months(v_month,
                                            -1 * row_number()
                                            over(partition by v_value order by
                                                 v_month)),
                                 'yyyymm')) diff
          from tmp_t)
 group by diff, v_value
 order by 1;

    結果爲

   

   

     全文完

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章