获取2个日期之间的月份日

时间:2016-06-10 07:30:39

标签: sql oracle date

每个月分别在两个日期之间找出天数差异的最简单方法是什么。

假设我有两个日期
2016年5月1日至5日 2016年6月2日至8日

我想要获得的结果是五月的天数和六月的天数(201605-6,201606-8)。

哪种方法最好?

2 个答案:

答案 0 :(得分:0)

在您的情况下,Numberstart_date 位于表格的同一行中,因此一个解决方案是:

创意:使用2 输入创建功能end_datestart_date输出:{{1 }}

练习:首先,创建一个函数end_date,返回每个string_with_days_in_each_month_between_two_dateGET_DAYS_EACH_MONTH_BETWEEN

的预期字符串
start_date

其次,将您的功能应用于end_date

CREATE OR REPLACE FUNCTION GET_DAYS_EACH_MONTH_BETWEEN
(start_date IN date, end_date IN date)
    RETURN  varchar2 IS
    result varchar2(4000);
BEGIN 
    WITH tmp AS
    (SELECT  
        LAST_DAY(ADD_MONTHS( start_date, level-1 ))
    FROM 
    (SELECT 
        start_date
        ,end_date
    FROM 
        dual)
    CONNECT BY 
        level <= MONTHS_BETWEEN(
                               TRUNC(end_date,'MM'),
                               TRUNC(start_date,'MM') )
    )
    , tmp1 AS
    (
    SELECT start_date date_col  FROM dual 
    UNION ALL
    SELECT end_date from dual
    UNION ALL
    SELECT * FROM tmp
    )
    SELECT 
        LISTAGG(result_col, ',') WITHIN GROUP (ORDER BY date_col) into result
    FROM 
        (SELECT 
            TO_CHAR(date_col,'yyyyMM') || '_' || TO_CHAR(date_col - LAG(date_col) OVER (ORDER BY date_col)) result_col
            , date_col
            ,ROW_NUMBER() OVER (ORDER BY date_col) rwn
        FROM
            tmp1
        ORDER BY 
            date_col 
        )
    WHERE 
        rwn <> 1;

    RETURN result;

END;

结果:

your table

重要提示:结果字符串的长度只有4000个字符,因此您应该考虑WITH test_table AS ( SELECT TO_DATE('2016-02-06','yyyy-mm-dd') start_date ,TO_DATE('2016-06-08','yyyy-mm-dd') end_date FROM DUAL UNION ALL SELECT TO_DATE('2016-05-06','yyyy-mm-dd') ,TO_DATE('2016-06-08','yyyy-mm-dd') FROM DUAL ) SELECT start_date, end_date ,GET_DAYS_EACH_MONTH_BETWEEN(start_date, end_date) result_col FROM test_table; start_date end_date result_col 2/6/2016 6/8/2016 201602_23,201603_31,201604_30,201605_31,201606_8 5/6/2016 6/8/2016 201605_25,201606_8 距离每个

的距离是否过长

该功能使用this link的建议结果来确定2个给定日期之间的所有月份。

答案 1 :(得分:0)

我做了一个递归方法:

with recur (dias, texto, nivel, d1,d2) as 
              (select last_day(d1)-d1 as dias, to_char(d1,'yyyymm')||'-' as texto,  0 as nivel, d1,d2 from dates union all --first date
               select case when (d2-trunc(add_months(d1, nivel+1),'month')+1) > extract(day from last_day(add_months(d1, nivel+1))) 
                       then extract(day from last_day(add_months(d1, nivel+1)))  
                       else d2-trunc(add_months(d1, nivel+1),'month')+1 end as dias, 
                       to_char(add_months(d1, nivel+1),'yyyymm')||'-' as texto,  nivel+1 as nivel ,d1,d2 from recur where trunc(add_months(d1, nivel+1),'month') < d2  --last month
               )
select d1, d2,listagg(texto||to_char(dias),',') within group (order by nivel) as resultado
 from recur
 group by d1,d2
 order by d1,d2;

2016年5月25日至2016年6月8日的输出

25-MAY-16   08-JUN-16   201605-6,201606-8

2016年5月25日至2017年7月8日的输出

25-MAY-16   08-JUL-17   201605-6,201606-30,201607-31,201608-31,201609-30,201610-31,201611-30,201612-31,201701-31,201702-28,201703-31,201704-30,201705-31,201706-30,201707-8