【问题标题】:Oracle End Of Month values for Date Range日期范围的 Oracle 月末值
【发布时间】:2017-04-12 22:00:09
【问题描述】:

Oracle 有一个last_day() 函数:

SELECT LAST_DAY(to_date('01/01/2016','DD/MM/YYYY')) from dual;

结果:

31/01/2016

如何获取日期范围内的 EndOfMonths 列表以在 WHERE 子句中使用,目前我使用的是一个大字符串,它不直观或未来证明:

SELECT * FROM Balances
WHERE TheDate IN
('31/Jan/2016','29/Feb/2016', '31/Mar/2016','30/Apr/2016', '31/May/2016','30/Jun/2016', '31/Jul/2016','31/Aug/2016',
'30/Sep/2016', '31/Oct/2016','30/Nov/2016')

我更喜欢使用函数来插入开始和结束日期。

【问题讨论】:

    标签: sql oracle date plsql


    【解决方案1】:

    尝试这样的方法来生成月份范围的最后一天:

    SELECT LAST_DAY(add_months(to_date('01/01/2016','DD/MM/YYYY'), level) )
    from dual
    CONNECT BY LEVEL <= 10
    

    将您需要的 10 个月更改为 # 个月。这假定“TheDate”是正确的 oracle DATE 类型。如果需要格式化为字符串,请使用 to_char 包装。

    @JeremyThompsons Months_Between 建议:

    SELECT LAST_DAY(add_months(to_date('01-01-1991','DD/MM/YYYY'), level) )
    from dual
    CONNECT BY LEVEL <=
    (SELECT MONTHS_BETWEEN 
       (TO_DATE('02-02-1999','MM-DD-YYYY'),
        TO_DATE('01-01-1991','MM-DD-YYYY') ) "Months"
        FROM dual);
    

    带有@mathguys 函数顺序建议的最终查询:

    SELECT * FROM Balances b
    WHERE TheDate IN
    (SELECT add_months(LAST_DAY(to_date('28/Feb/2015','DD-MM-YYYY')), level) 
    from dual
    CONNECT BY LEVEL <=
    (SELECT MONTHS_BETWEEN 
       (TO_DATE('30/Nov/2016','DD-MM-YYYY'),
        TO_DATE('28/Feb/2015','DD-MM-YYYY') ) "Months"
        FROM dual));
    

    还有一个@mathguys 优化,不需要标量子查询:

    SELECT * FROM Balances b
    WHERE TheDate IN
    (SELECT add_months(LAST_DAY(to_date('28/Feb/2015','DD-MM-YYYY')),level)
    from dual
    CONNECT BY LEVEL <= MONTHS_BETWEEN 
       (TO_DATE('30/Nov/2016','DD-MM-YYYY'),
        TO_DATE('28/Feb/2015','DD-MM-YYYY')) );
    

    【讨论】:

    • 所以只需一个月_Between 完成它,我会编辑你的答案,谢谢
    • add_months 可以与第一个参数一起使用月末,在这种情况下它只返回月末。然后您可以将呼叫保存到last_day()。尝试例如select add_months(last_day(sysdate), level) from dual connect by level &lt;= 12; 并根据需要进行调整。
    • 进一步增强,如果输入月末日期,LAST_DAY 可以消除,为什么我提到这是因为@mathguy 的建议,Oracle 的ADD_MONTHS 功能不是很明显智能并在后台进行了优化,您可以使用 2 月 28 日或 29 日、4 月 30 日,但不能使用 3 月 30 日。伟大的团队合作伙伴!
    • @JeremyThompson - months_between() 可以在 CONNECT BY LEVEL 条件中单独使用,它不需要围绕它的标量子查询。它返回一个可以直接在条件中使用的数字。
    【解决方案2】:

    您可以创建如下函数,该函数将返回所有月份的月末:

    create or replace function getEndOfMonths return varchar2 as
        cnt number;
        current_year varchar2(5);
        end_of_months varchar2(180) := '';
        end_of_month varchar2(13);
    begin
        select to_char(sysdate,'YYYY') into current_year from dual;
        for cnt in 1..12 loop
            SELECT LAST_DAY(to_date('01/'||cnt||'/'||current_year,'DD/MM/YYYY')) into end_of_month from dual;
            end_of_months := end_of_months||','||end_of_month;
        end loop;
        return substr(end_of_months,2);
    end;
    /
    

    更新: 以下基于月份范围:

    create or replace function getEndOfMonths(start_month number, end_month number) return varchar2 as
        cnt number;
        current_year varchar2(5);
        end_of_months varchar2(180) := '';
        end_of_month varchar2(13);
    begin
        select to_char(sysdate,'YYYY') into current_year from dual;
        for cnt in start_month..end_month loop
            SELECT LAST_DAY(to_date('01/'||cnt||'/'||current_year,'DD/MM/YYYY')) into end_of_month from dual;
            end_of_months := end_of_months||','||end_of_month;
        end loop;
        return substr(end_of_months,2);
    end;
    /
    

    【讨论】:

    • 那行不通。那是一个大字符串,而不是 IN 列表。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-23
    • 2014-06-09
    相关资源
    最近更新 更多