簡體   English   中英

Oracle SQL-獲取指定月份兩個日期之間的天數

[英]Oracle SQL - get number of days between two dates for a specified month

我想獲取兩個日期之間的天數,但僅用於指定的月份。

樣本數據:

datefrom  dateto    
28/1/2016 15/2/2016 
10/2/2016 3/3/2016  
5/2/2016  16/2/2016 
20/1/2016 10/3/2016

2月預期產量:

datefrom  dateto    numofdays
28/1/2016 15/2/2016 15
10/2/2016 3/3/2016  19
5/2/2016  16/2/2016 11
20/1/2016 10/3/2016 29

具有相同日期的一月份的預期產量:

datefrom  dateto    numofdays
28/1/2016 15/2/2016 4
10/2/2016 3/3/2016  0
5/2/2016  16/2/2016 0
20/1/2016 10/3/2016 11

具有相同日期的3月的預期產量:

datefrom  dateto    numofdays
28/1/2016 15/2/2016 0
10/2/2016 3/3/2016  3
5/2/2016  16/2/2016 0
20/1/2016 10/3/2016 10

月份將由參數(當通過ODBC輸出到excel中時)由月份號1到12選擇。

2月不是一個月,它是一年中一個月的通用名稱。 正確的“月份”是2016年2月或2017年2月等。根據您期望的輸出,我假設您的意思是2016年2月。

這個問題是微不足道的。 無論您定義月份,您都可以標識該月的第一天和最后一天。 例如,如果您將月份輸入為六個字符的字符串: input = '201602' ,則可以使用類似

to_date(input, 'yyyymm')                as month_start, 
last_day(to_date(input, 'yyyymm'))      as month_end

然后像這樣計算天數:

准備 (在SQLPlus中):

SQL> variable input varchar2(30)
SQL> exec :input := '201602';

PL/SQL procedure successfully completed.

SQL> alter session set nls_date_format = 'dd/mm/yyyy';

查詢

with
     test_dates ( datefrom, dateto ) as (
       select to_date('28/1/2016', 'dd/mm/yyyy'), to_date('15/2/2016', 'dd/mm/yyyy') from dual union all
       select to_date('10/2/2016', 'dd/mm/yyyy'), to_date('3/3/2016' , 'dd/mm/yyyy') from dual union all
       select to_date('5/2/2016' , 'dd/mm/yyyy'), to_date('16/2/2016', 'dd/mm/yyyy') from dual union all
       select to_date('20/1/2016', 'dd/mm/yyyy'), to_date('10/3/2016', 'dd/mm/yyyy') from dual
     )
--  end of test data; solution (SQL query) begins below this line
select t.datefrom, t.dateto, to_char(to_date(:input, 'yyyymm'), 'MON yyyy') as month,
       case when t.datefrom > m.month_end or t.dateto < m.month_start then 0
            else least(t.dateto, m.month_end) - greatest(t.datefrom, m.month_start) + 1
            end as number_of_days
from   test_dates t cross join 
                  ( select to_date(:input, 'yyyymm') as month_start,
                           last_day(to_date(:input, 'yyyymm')) as month_end 
                    from   dual) m
;

輸出 :(注意:“所需輸出”中的數字不正確)

DATEFROM   DATETO     MONTH    NUMBER_OF_DAYS
---------- ---------- -------- --------------
28/01/2016 15/02/2016 FEB 2016             15
10/02/2016 03/03/2016 FEB 2016             20
05/02/2016 16/02/2016 FEB 2016             12
20/01/2016 10/03/2016 FEB 2016             29

4 rows selected.

您可以使用分層查詢或遞歸CTE將每個日期范圍擴展到其組成天數; 然后計算與指定月份匹配的數量:

with r (datefrom, dateto, dateday) as (
  select datefrom, dateto, datefrom
  from t
  union all select datefrom, dateto, dateday + 1
  from r
  where dateday < dateto
)
select datefrom, dateto,
  to_char(to_date(:monthnum, 'MM'), 'MON', 'NLS_DATE_LANGUAGE=ENGLISH') as month,
  count(case when to_char(dateday, 'MM') = :monthnum then dateday end) as numofdays
from r
group by datefrom, dateto
order by datefrom, dateto;

依次對綁定變量使用1、2和3會生成:

DATEFROM  DATETO    MONTH         NUMOFDAYS
--------- --------- ------------ ----------
20-JAN-16 10-MAR-16 JAN                  12
28-JAN-16 15-FEB-16 JAN                   4
05-FEB-16 16-FEB-16 JAN                   0
10-FEB-16 03-MAR-16 JAN                   0

DATEFROM  DATETO    MONTH         NUMOFDAYS
--------- --------- ------------ ----------
20-JAN-16 10-MAR-16 FEB                  29
28-JAN-16 15-FEB-16 FEB                  15
05-FEB-16 16-FEB-16 FEB                  12
10-FEB-16 03-MAR-16 FEB                  20

DATEFROM  DATETO    MONTH         NUMOFDAYS
--------- --------- ------------ ----------
20-JAN-16 10-MAR-16 MAR                  10
28-JAN-16 15-FEB-16 MAR                   0
05-FEB-16 16-FEB-16 MAR                   0
10-FEB-16 03-MAR-16 MAR                   3

或者,您可以生成指定月份的所有日期,並獲取兩個集合的相交。

由於您僅指定月份而不是年份,因此假設范圍永遠不會超過一年-如果是,則要計算兩個年份中出現的月份中的天數。

它還假設相同的日期范圍不會出現多次; 如果這樣做,則分組和計數將關閉。 大概您的真實數據具有一個尚未顯示的密鑰,可以將其包含在CTE和group-by子句中,以避免出現這種情況。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM