【问题标题】:Get month days between 2 dates获取两个日期之间的月份天数
【发布时间】:2016-06-10 07:30:38
【问题描述】:

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

假设我有两个日期
2016 年 5 月 1.25 日
2016 年 6 月 2.08 日

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

最好的方法是什么?

【问题讨论】:

  • 您希望使用此输入输出什么:1.25 May 2015 2.08 Jun 2016?多行?用逗号分隔的字符串?...
  • 字符串分隔的逗号正是这种格式 201605-6,201606-8。 YearMonth-Numberofdays,yearmonth-numberofdays ...
  • 两个日期是否在一个表格的一行中?日期可以相隔多年吗?
  • 是的,日期在同一行,可以相隔多年

标签: sql oracle date


【解决方案1】:

在您的情况下,start_dateend_date 在表格的同一行,因此一种解决方案是:

想法:用 2 个输入创建一个函数start_dateend_date输出string_with_days_in_each_month_between_two_date

实践:首先,创建一个函数GET_DAYS_EACH_MONTH_BETWEEN,分别返回预期的字符串start_dateend_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

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                              

重要提示:结果字符串的长度只有 4000 个字符,所以您应该考虑start_dateend_date 何时距离太远

该函数使用来自this link 的建议结果来生成两个给定日期之间的所有月份。

【讨论】:

    【解决方案2】:

    我做了一个递归的方法:

    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
    

    【讨论】:

      猜你喜欢
      • 2021-07-09
      • 1970-01-01
      • 2017-05-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-12-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多