如何在没有永恒循环的情况下为每个时期进行递归?

时间:2017-10-12 05:27:35

标签: sql oracle

当我尝试以递归方式计算每个plan_period的周期时,我的查询卡在永恒循环中。以下是我的尝试:

WITH p (period_id, start_period, end_period  )
         AS (SELECT 
                    PERIOD_VERSIO,
                    To_date(FROM_PERIOD, 'YYYYMM'),
                    To_date(TO_PERIOD, 'YYYYMM')
             FROM   SOR_MAP_PLAN_PERIOD),
         date_ranges
         AS (SELECT 
                   distinct
                    period_id,
                    To_char(start_period, 'YYYYMM') as START_PERIOD,
                    To_char(Add_months (start_period, LEVEL - 1), 'YYYYMM') as END_PERIOD
             FROM   p
             CONNECT BY LEVEL <= Months_between( end_period, start_period ) + 1)


    SELECT d.period_id as "KEY",
        --   d.start_period,
           d.end_period as PERIOD,
         e.end_period as PLAN_PERIOD
    FROM   date_ranges d
    --order by 3,2

          full outer join (SELECT period_id,end_period
                       FROM   date_ranges
                       ) e on e.period_id=d.period_id
    ORDER  BY 3,  2, 1

    ; 
Parameter table:

    PERIOD_VERSIO   FROM_PERIOD TO_PERIOD
    201612_BU       201701      201712
    201705_STR      201801      202012
    201706_SRT1     201801      202012
    201709_LE       201710      201809

通缉结果:

PERIOD_VERSIO   PERIOD  PLAN_PERIOD
201612_BU       201701  201701
201612_BU       201702  201701
201612_BU       201703  201701
201612_BU       201704  201701
201612_BU       201705  201701
201612_BU       201706  201701
201612_BU       201707  201701
201612_BU       201708  201701
201612_BU       201709  201701
201612_BU       201710  201701
201612_BU       201711  201701
201612_BU       201712  201701
201612_BU       201701  201702
201612_BU       201702  201702
201612_BU       201703  201702
201612_BU       201704  201702
…..     
…..     
201706_SRT1     201801  201801
201706_SRT1     201802  201801
201706_SRT1     201803  201801
201706_SRT1     201804  201801
201706_SRT1     201805  201801
201706_SRT1     201806  201801
201706_SRT1     201808  201801
201706_SRT1     201808  201801
201706_SRT1     201809  201801
201706_SRT1     201810  201801
201706_SRT1     201811  201801
201706_SRT1     201812  201801
……      
201706_SRT1     201801  202012
201706_SRT1     201802  202012
201706_SRT1     201803  202012
201706_SRT1     201804  202012
201706_SRT1     201805  202012
201706_SRT1     201806  202012
201706_SRT1     201808  202012
201706_SRT1     201808  202012
201706_SRT1     201809  202012
201706_SRT1     201810  202012
201706_SRT1     201811  202012
201706_SRT1     201812  202012

2 个答案:

答案 0 :(得分:1)

这可以在纯SQL中完成。

首先,我们有一个递归的WITH子句,它生成每个period_versio'. Then there's join two instances of that subquery which produces all the permutations of generated months for the period_versio&#39;的开始和结束时段所涵盖的所有月份。

with mths (period_id, period_st, period_end, lvl) as (
    select period_versio, 
           cast(to_date(from_period, 'yyyymm') as date), 
           cast(to_date(to_period, 'yyyymm') as date), 
           1 
    from sor_map_plan_period
    union all
    select period_id, 
           cast(add_months(period_st, 1) as date), 
           cast(period_end as date), 
           lvl+1
    from mths
    where lvl < months_between(period_end, period_st)
)   
select t1.period_id as period_versio
       ,to_char( t1.period_st, 'yyyymm') as period
       ,to_char( t2.period_end, 'yyyymm') as plan_period
from       
( select period_id,
       period_st
  from   mths) t1
join 
(select period_id,
             period_end
 from   mths) t2
on t1.period_id = t2.period_id
order by 1, 2, 3
/

Oracle 11gR2中引入了递归WITH子句。在传递日期时,它有一个令人讨厌的错误,投掷ORA-01790。因此需要围绕显然已经过日期的事物看起来很奇怪的CAST表达式。如果您正在使用12c,则可能不需要它们。

答案 1 :(得分:0)

您的查询可能就像这样简单:

select period_versio
      ,ym as period
      ,from_period plan_period
  from parameter_t a  
  join periods_t   b on(
       b.ym >= a.from_period 
   and b.ym <= a.to_period
  );

...如果你有一个句号表......如果你打算与他们一起工作,你应该拥有它。以下是如何创建2000 - 2030年期间的表格。

create table periods_t(
   ym    number not null
  ,year  number not null
  ,month number not null
  ,primary key(ym)
);

insert 
  into periods_t(ym, year, month)
select year || lpad(month, 2, '0') as ym
      ,year
      ,month
  from (select 1999 + level as year from dual connect by level <= 30) y
      ,(select level as month       from dual connect by level <= 12) m;

我从示例参数

中假设了以下表结构
create table parameter_t(
   period_versio varchar2(20) not null
  ,from_period   number(6)    not null
  ,to_period     number(6)    not null
);

insert into parameter_t values('201612_BU',     201701, 201712);
insert into parameter_t values('201705_STR',    201801, 202012);
insert into parameter_t values('201706_SRT1',   201801, 202012);
insert into parameter_t values('201709_LE',     201710, 201809);