1

Oracle の months_between 関数の背後にある正確なロジックは何ですか?
私はこのクエリを試しました:

SELECT D1, 
       D2, 
       MONTHS_BETWEEN (D1, D2) DIFF,
       (D1-D2)/31 MANUAL_CALC1,
       (D1-D2)/30 MANUAL_CALC2,
       (D1-D2)/29 MANUAL_CALC3,
       (D1-D2)/28 MANUAL_CALC4
FROM (SELECT TO_DATE('07-03-2014', 'DD-MM-YYYY') D1, 
             TO_DATE('04-02-2014', 'DD-MM-YYYY') D2
        FROM DUAL);

結果は次のようになりました:
DIFF: 1.09
MANUAL_CALC1: 1
MANUAL_CALC2: 1.03
MANUAL_CALC3: 1.06
MANUAL_CALC4: 1.10

Oracle パッケージを Java プログラムに変換していますが、まったく同じ結果を生成する必要があります。しかし、この 1 つの関数 (months_between) だけでパーティーが台無しになります。

4

2 に答える 2

0
SELECT
    a.dt_base,
    a.dt,
    a.months,
    a.days,
    a.mms,
    a.my_months,
    a.bias,
    a.day_part,
    a.my_add_months
FROM
    (
        SELECT
            a.dt_base,
            a.dt,
            a.months,
            a.days,
            a.mms,
            a.my_months,
            31 - TO_NUMBER(TO_CHAR(LAST_DAY(ADD_MONTHS(a.dt_base,TRUNC(a.months))),'dd')) bias,
            ((a.months - TRUNC(a.months)) * 31) day_part,
            CASE WHEN TO_CHAR(ADD_MONTHS(a.dt_base,TRUNC(a.months)),'yyyymm') != TO_CHAR((ADD_MONTHS(a.dt_base,TRUNC(a.months)) + ((a.months - TRUNC(a.months)) * 31)),'yyyymm') THEN
                ADD_MONTHS(a.dt_base,TRUNC(a.months)) + ((a.months - TRUNC(a.months)) * 31) - (31 - TO_NUMBER(TO_CHAR(LAST_DAY(ADD_MONTHS(a.dt_base,TRUNC(a.months))),'dd')))
            ELSE 
                ADD_MONTHS(a.dt_base,TRUNC(a.months)) + ((a.months - TRUNC(a.months)) * 31)
            END my_add_months
        FROM
            (
                SELECT
                    a.dt_base,
                    a.dt,
                    a.months,
                    a.days,
                    a.mms,
                    mms + days / 31 my_months
                FROM
                    (
                        SELECT
                            a.dt_base,
                            a.dt,
                            a.months,
                            CASE WHEN TO_CHAR(a.dt_base,'dd') > to_char(a.dt,'dd') THEN
                                31 - TO_NUMBER(TO_CHAR(a.dt_base,'dd')) + TO_NUMBER(TO_CHAR(a.dt,'dd'))
                            ELSE
                                TO_NUMBER(TO_CHAR(a.dt,'dd')) - TO_NUMBER(TO_CHAR(a.dt_base,'dd'))
                            END days
                            , CASE WHEN TO_CHAR(a.dt_base,'dd') > TO_CHAR(a.dt,'dd') THEN
                                ( TO_NUMBER(TO_CHAR(a.dt,'yyyy')) * 12 + TO_NUMBER(TO_CHAR(a.dt,'mm')) )
                                -
                                ( TO_NUMBER(TO_CHAR(a.dt_base,'yyyy')) * 12 + TO_NUMBER(TO_CHAR(a.dt_base,'mm')) )
                                - 1
                            ELSE
                                ( TO_NUMBER(TO_CHAR(a.dt,'yyyy')) * 12 + TO_NUMBER(TO_CHAR(a.dt,'mm')) )
                                -
                                ( TO_NUMBER(TO_CHAR(a.dt_base,'yyyy')) * 12 + TO_NUMBER(TO_CHAR(a.dt_base,'mm')) )
                            END mms
                        FROM
                            (
                                SELECT
                                    dt_base,
                                    dt,
                                    MONTHS_BETWEEN(dt,dt_base) months
                                FROM
                                    (
                                        SELECT
                                            TRUNC(sysdate,'dd') dt_base,
                                            TRUNC(sysdate,'dd') + level - 1 dt
                                        FROM    dual
                                        CONNECT BY level < 36500
                                    ) a
                            ) a
                    )a
            ) a
    ) a
WHERE   a.dt != a.my_add_months
于 2015-07-10T02:31:56.440 に答える