これは、ANSI で指定されている予期される動作です。この AskTomを参照してください。2013 年 7 月 30 日に 2 か月足すと、2013 年 9 月 30 日になります。これは完全に理解できると思います。2013 年 7 月 31 日に 2 か月を追加すると、次のようになります。2013 年 9 月 31 日はありません。9 月は 30 日しかありません。では、システムは何をするべきなのでしょうか? 2013 年 9 月 30 日になるはずですか?2013 年 10 月 1 日と表示されますか? これらはどちらも正しくありません。月の値を 2 か月前に変更するように要求しました。OK、それを試みて、結果の日付が無効であることを発見したため、エラーがスローされます。
まあ。
しかし、ありがたいことに、私たちは単なる人間ではありません。私たちは優れた存在です。私たちはソフトウェア開発者です。マニュアルがあります!!!! 私たちは神々の近くにいます!!!!!!!!!!!!
そこで、マニュアルを参照すると、ADD_MONTHS 関数が利用可能であることがわかります。これは、ここで探しているほとんどのことを実行します。ただし、ADD_MONTHS は DATE 値でのみ動作するため、保存するために余分な操作を行わないと、小数秒が失われます。しかし、私が言ったように、私たちはソフトウェア開発者です...
例:
DECLARE
tsIn TIMESTAMP := TO_TIMESTAMP('31-JUL-2013 17:31:01', 'DD-MON-YYYY HH24:MI:SS');
tsOut TIMESTAMP;
nFrac_secs NUMBER;
strBuffer VARCHAR2(1000);
strFrac_secs VARCHAR2(1000);
BEGIN
tsIn := tsIn + NUMTODSINTERVAL(0.1234, 'SECOND');
strBuffer := TO_CHAR(tsIn);
strFrac_secs := SUBSTR(strBuffer, -10, 7);
DBMS_OUTPUT.PUT_LINE('tsIn=' || tsIn);
DBMS_OUTPUT.PUT_LINE('strBuffer=' || strBuffer);
DBMS_OUTPUT.PUT_LINE('strFrac_secs=' || strFrac_secs);
nFrac_secs := TO_NUMBER(strFrac_secs);
DBMS_OUTPUT.PUT_LINE('nFrac_secs=' || nFrac_secs);
tsOut := ADD_MONTHS(tsIn, 2);
DBMS_OUTPUT.PUT_LINE('tsOut before restoring fractional seconds=' || tsOut);
tsOut := tsOut + NUMTODSINTERVAL(nFrac_secs, 'SECOND');
DBMS_OUTPUT.PUT_LINE('tsOut after restoring fractional seconds=' || tsOut);
END;
したがって、基本的に、区間演算を実行しようとすると、Oracle は&^#@$# ANSI 仕様に従い、ばかげた動作をします。次に、多かれ少なかれ必要なことを行う関数(公平を期すために文書化されています)を提供しますが、DATE値に対してのみ行います。これがいわゆる「職安」だと思いますが…
:-)
共有してお楽しみください。