Oracle - 查找月度,季度和年度日期

时间:2015-12-02 09:04:49

标签: sql oracle date

我有一张桌子:

表1

start        end
1/jan/2012   15/jan/2012
1/feb/2013   5/april/2013

我需要找到所有可能的月度,季度和年度时间范围。对于前。

1)     1 / jan / 2012 15 / jan / 2012

将介于:

之间
1/jan/2012   31/jan/2012
1/jan/2012   31/march/2012
1/jan/2012   31/dec/2012

2)     1 / feb / 2013 5 / april / 2013

将介于:

之间
1/feb/2013   28/feb/2013
1/march/2013 31/march/2013
1/april/2013 30/april/2013
1/jan/2013   31/march/2013
1/april/2013 30/june/2013
1/jan/2013   31/dec/2013

是否可以通过SQL查询来获取所有可能的日期组合?

3 个答案:

答案 0 :(得分:2)

希望有所帮助:

-- test data  
with table1 as
 (select 1 as id,
         to_date('20120101', 'YYYYMMDD') as start_dt,
         to_date('20120115', 'YYYYMMDD') as end_dt
    from dual
  union all
  select 2 as id,
         to_date('20130201', 'YYYYMMDD') as start_dt,
         to_date('20130405', 'YYYYMMDD') as end_dt
    from dual),

-- get sequences in range [0..max date interval-1]
idx_tab as
 (select level - 1 as idx
    from dual
  connect by level < (select max(end_dt - start_dt) from table1)),

-- expand interval [start_dt; end_dt] by day
dt_tb as
 (select t.id, t.start_dt, t.end_dt, t.start_dt + i.idx as dt
    from table1 t, idx_tab i
   where t.start_dt + idx <= t.end_dt)

select 'Month-' || to_char(dt, 'YYYY-MM'), id, start_dt, end_dt
  from dt_tb
union
select 'Quarter-' || to_char(dt, 'YYYY-Q'), id, start_dt, end_dt
  from dt_tb
union
select 'Year-' || to_char(dt, 'YYYY'), id, start_dt, end_dt
  from dt_tb
 order by 1, 2;

答案 1 :(得分:1)

SQL Fiddle

查询1

WITH dates ( date_start, date_end ) AS (
  SELECT DATE '2013-02-01', DATE '2013-04-05' FROM DUAL
)
SELECT 'M' AS period,
       ADD_MONTHS( TRUNC( date_start, 'MM' ), LEVEL - 1 ) AS range_start,
       ADD_MONTHS( TRUNC( date_start, 'MM' ), LEVEL ) - INTERVAL '1' DAY AS range_end
FROM   dates
CONNECT BY 
       ADD_MONTHS( TRUNC( date_start, 'MM' ), LEVEL - 1 ) <= TRUNC( date_end, 'MM' )
UNION ALL
SELECT 'Q' AS period,
       ADD_MONTHS( TRUNC( date_start, 'Q' ), 3 * ( LEVEL - 1) ) AS range_start,
       ADD_MONTHS( TRUNC( date_start, 'Q' ), 3 * LEVEL ) - INTERVAL '1' DAY AS range_end
FROM   dates
CONNECT BY 
       ADD_MONTHS( TRUNC( date_start, 'Q' ), 3 * (LEVEL - 1) ) <= TRUNC( date_end, 'Q' )
UNION ALL
SELECT 'Y' AS period,
       ADD_MONTHS( TRUNC( date_start, 'Y' ), 12 * ( LEVEL - 1) ) AS range_start,
       ADD_MONTHS( TRUNC( date_start, 'Y' ), 12 * LEVEL ) - INTERVAL '1' DAY AS range_end
FROM   dates
CONNECT BY 
       ADD_MONTHS( TRUNC( date_start, 'Y' ), 12 * (LEVEL - 1) ) <= TRUNC( date_end, 'Y' )

<强> Results

| PERIOD |                RANGE_START |                  RANGE_END |
|--------|----------------------------|----------------------------|
|      M | February, 01 2013 00:00:00 | February, 28 2013 00:00:00 |
|      M |    March, 01 2013 00:00:00 |    March, 31 2013 00:00:00 |
|      M |    April, 01 2013 00:00:00 |    April, 30 2013 00:00:00 |
|      Q |  January, 01 2013 00:00:00 |    March, 31 2013 00:00:00 |
|      Q |    April, 01 2013 00:00:00 |     June, 30 2013 00:00:00 |
|      Y |  January, 01 2013 00:00:00 | December, 31 2013 00:00:00 |

答案 2 :(得分:1)

WITH date_range AS (
    SELECT TO_DATE('2012-01-01', 'YYYY-MM-DD') AS start_date, TO_DATE('2012-01-15', 'YYYY-MM-DD') AS end_date FROM DUAL
    UNION
    SELECT TO_DATE('2012-02-01', 'YYYY-MM-DD') AS start_date, TO_DATE('2012-04-05', 'YYYY-MM-DD') AS end_date FROM DUAL
), monthly_range AS (
    SELECT dr.start_date
        , dr.end_date
        , 'Monthly' AS range_type
        , ADD_MONTHS(TRUNC(dr.start_date, 'MM'), LEVEL - 1) AS month_start
        , ADD_MONTHS(LAST_DAY(dr.start_date), LEVEL - 1) AS month_end
    FROM date_range dr
    CONNECT BY LEVEL <= CEIL(MONTHS_BETWEEN(dr.end_date, dr.start_date))
), quarterly_range AS (
    SELECT 
          dr.start_date
        , dr.end_date
        , 'Quarterly' AS range_type
        , ADD_MONTHS(TRUNC(dr.start_date, 'MM'), (LEVEL - 1) * 3) AS range_start
        , ADD_MONTHS(TRUNC(dr.start_date, 'MM'), LEVEL * 3) - 1 AS range_end

    FROM date_range dr
    CONNECT BY LEVEL <= CEIL(MONTHS_BETWEEN(dr.end_date, dr.start_date)/3)
), yearly_range AS (
    SELECT 
          dr.start_date 
        , dr.end_date
        , 'Yearly' AS range_type
        , ADD_MONTHS(TRUNC(dr.start_date, 'MM'), (LEVEL - 1) * 12) AS range_start
        , ADD_MONTHS(TRUNC(dr.start_date, 'MM'), LEVEL * 12) - 1 AS range_end
    FROM date_range dr
    CONNECT BY LEVEL <= CEIL(MONTHS_BETWEEN(dr.end_date, dr.start_date)/12)
)
SELECT mr.* FROM monthly_range mr
UNION
SELECT qr.* FROM quarterly_range qr
UNION
SELECT yr.* FROM yearly_range yr
ORDER BY 1,2,3,4;