[英]Oracle How to list last days of months between 2 dates
我設法獲得了兩個日期之間的所有日子。 但我想獲得兩個日期之間的所有月份的最后一天(使用一個請求)。
兩個日期之間的所有天數:
select to_date('01/01/2000','dd/mm/yyyy') + (LEVEL-1) as jour
from dual
connect by level <= to_date('31/12/2050','dd/mm/yyyy')-to_date('01/01/2000','dd/mm/yyyy')
當月的最后一天:
select LAST_DAY(sysdate) FROM dual
我不知道如何混合兩者並獲得預期結果:
20000131
20000228
20000331
etc...
我想那將是DISTINCT
+ LAST_DAY
。
設置日期格式(使其與您的匹配;或者,使用適當的格式掩碼將TO_CHAR
應用於jour
值):
SQL> alter session set nls_Date_format = 'yyyymmdd';
Session altered.
我將時間跨度縮短到 2 年(以節省空間:))。
SQL> select distinct last_day(to_date('01/01/2000','dd/mm/yyyy') + (LEVEL-1)) as jour
2 from dual
3 connect by level <= to_date('31/12/2002','dd/mm/yyyy')-to_date('01/01/2000','dd/mm/yyyy')
4 order by 1;
JOUR
--------
20000131
20000229
20000331
20000430
20000531
20000630
20000731
20000831
<snip>
20020630
20020731
20020831
20020930
20021031
20021130
20021231
36 rows selected.
SQL>
我喜歡使用標准遞歸查詢而不是 Oracle 特定的CONNECT BY
語法。 在這里,您可以枚舉月份的開始,然后抵消到月份的結束:
with cte (dt) as (
select date '2020-01-01' dt from dual
union all
select dt + interval '1' month from cte where dt + interval '1' month < date '2051-01-01'
)
select last_day(dt) dt from cte order by dt
請注意,這使用標准日期文字( date 'YYYY-MM-DD'
)而不是to_date()
- 這使查詢更短,並且再次更標准。
| DT | | :-------- | | 31-JAN-20 | | 29-FEB-20 | | 31-MAR-20 | | 30-APR-20 | | 31-MAY-20 | ... | 31-OCT-50 | | 30-NOV-50 | | 31-DEC-50 |
您可以使用 CONNECT BY 查詢執行此操作。 (您也可以使用遞歸查詢來完成,就像 GMB 提出的那樣,但它必須進行調整以解決您提出的問題 - 它應該允許輸入開始和結束日期,如果沒有,它應該返回零行兩個日期之間的月末。)
在下面的查詢中,我使用 WITH 子句來給出開始和結束日期。 更有可能的是,在您的問題中,它們是綁定變量。 (或者它們是從表格中讀取的?)
注意 START WITH 子句。 CONNECT BY 條件僅適用於 2 級及以上; 對於 level=1 的 START WITH 條件,對於給定日期之間沒有月末的情況(例如,在同一年的 1 月 10 日和 1 月 23 日之間)。
with
input_dates(start_dt, end_dt) as (
select date '2020-01-22', date '2020-04-03' from dual
)
select add_months(last_day(start_dt), level - 1) as eom
from input_dates
start with last_day(start_dt) <= end_dt
connect by add_months(last_day(start_dt), level - 1) <= end_dt
;
EOM
----------
2020-01-31
2020-02-29
2020-03-31
您的初始查詢只需要進行一些調整。 而不是僅僅級別 1(每天結束)將其轉換為每月增量“級別 1)* 間隔 '1' 月。然后對於連接,只需獲取所需日期之間的月份。注意:我已轉換為 ISO日期的標准格式而不是 to_date 函數。使查詢更短且更易於閱讀。
select last_day(date '2000-01-01' + (level-1)*interval '1' month) as jour
from dual
connect by level <= 1+months_between(date '2050-12-31',date '2000-01-01');
您可以使用遞歸子查詢。
這將適用於:
WITH input_ranges ( start_date, end_date ) AS (
-- Should return a single row.
SELECT DATE '2020-01-31', DATE '2020-02-01' FROM DUAL UNION ALL
-- Should return multiple rows.
SELECT DATE '2021-02-01', DATE '2021-06-01' FROM DUAL UNION ALL
-- Should not return any rows as there is no end of the month in the range.
SELECT DATE '2021-10-06', DATE '2021-10-20' FROM DUAL UNION ALL
-- Should work even though February does not have 30 days.
SELECT DATE '2022-01-30', DATE '2022-03-02' FROM DUAL
),
month_ends ( month_end, end_date ) AS (
SELECT LAST_DAY( start_date ),
end_date
FROM input_ranges
WHERE LAST_DAY( start_date ) <= end_date
UNION ALL
SELECT ADD_MONTHS( month_end, 1 ),
end_date
FROM month_ends
WHERE ADD_MONTHS( month_end, 1 ) <= end_date
)
SELECT month_end
FROM month_ends
ORDER BY month_end;
哪些輸出:
\n | MONTH_END |\n | :------------------ |\n | 2020-01-31 00:00:00 |\n | 2021-02-28 00:00:00 |\n | 2021-03-31 00:00:00 |\n | 2021-04-30 00:00:00 |\n | 2021-05-31 00:00:00 |\n | 2022-01-31 00:00:00 |\n | 2022-02-28 00:00:00 |\n
db<> 在這里擺弄
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.