sql >> データベース >  >> RDS >> Oracle

ORA-01873:最高の精度

    数値の「エポック」番号の1つが、numtodsinterval()に対して大きすぎる(または小さすぎる)ようです 処理する関数。秒数として渡すことができる最大値は2^31-1です:

    SQL> select numtodsinterval(power(2,31) - 1, 'SECOND') as interval from dual; 
    
    INTERVAL     
    --------------
    24855 3:14:7.0
    
    SQL> select numtodsinterval(power(2,31), 'SECOND') as interval from dual; 
    
    SQL Error: ORA-01873: the leading precision of the interval is too small
    01873. 00000 -  "the leading precision of the interval is too small"
    *Cause:    The leading precision of the interval is too small to store the
               specified interval.
    *Action:   Increase the leading precision of the interval or specify an
               interval with a smaller leading precision.
    

    エポックとして、最大許容秒数は2038-01-1903:14:07を表します。 これは、2038年問題です 、本質的に。

    負の数でもそこにたどり着くことができます:

    SQL> select numtodsinterval(-2208988800, 'SECOND') as interval from dual;
    
    SQL Error: ORA-01873: the leading precision of the interval is too small
    

    -power(2, 31)の使用 正の値に折り返されますが、そのエラーよりも低い値は次のとおりです。

    SQL> select numtodsinterval(power(2,31) - 1, 'SECOND') as interval from dual;
    
    INTERVAL     
    --------------
    24855 3:14:7.0
    
    SQL> select numtodsinterval(-power(2,31), 'SECOND') as interval from dual;
    
    INTERVAL     
    --------------
    24855 3:14:8.0
    
    SQL> select numtodsinterval(-power(2,31) - 1, 'SECOND') as interval from dual;
    
    SQL Error: ORA-01873: the leading precision of the interval is too small
    

    1000で除算しているため、列FからKの1つに2147483647000を超える値があります。これはかなり簡単に見つけることができます。これらの列にもチェック制約を追加して、設定できないようにすることを検討してください。 high-列の値が1000 * (power(2, 31) - 1)以下であることを確認します 。そして、ゼロより大きいか、-1000 * (power(2, 31)

    where Col1 = 123のようなフィルターがある場合にエラーが発生しない理由 フィルタ(述語)がビュークエリにプッシュアップされ、値が高すぎる行は評価されないということです。おそらく、そのような値は1つだけで、そのcol1 値はではありません 123とそのcol2 値はではありません 'xyz'。問題のある行を特定し、実際のcol1を使用してフィルタリングする場合 値はまだエラーになります。フィルタがない場合、評価はすべての行に対して行われます。

    あなたが持っている特定の負の数は魔法の数のようです:

    SQL> select date '1970-01-01' - 2208988800/86400 from dual;
    
    DATE'1970-01-01'-2208988800/86400
    ---------------------------------
    1900-01-01 00:00:00              
    

    それを除外したい場合は、ビュー定義を変更して、フィルターを追加する必要があります(例:

    )。
    ...
    AND tab2.colh > 0
    

    または、列式を変更して処理するか、厳密に調整してnullのままにするか、おそらくより便利にその魔法の日付を返します。

        TO_CHAR(CASE WHEN tab2.colh = -2208988800000 THEN DATE'1900-01-01'
          ELSE DATE'1970-01-01' + NUMTODSINTERVAL( tab2.colh / 1000,'SECOND')
          END, 'YYYY/MM/DD HH24:MI:SS') AS Col13,
    

    間隔の使用から日付演算の使用に変更することもできます:

        TO_CHAR(DATE'1970-01-01' + ( tab2.colh / 86400000 ), 'YYYY/MM/DD HH24:MI:SS') AS Col13,
    

    ただし、colhでない限り、クエリではなくビュー定義を変更する必要があります。 は選択リストに含まれていますが(そうではないようです)、除外することしかできませんでした。オプティマイザーがクエリを処理した方法によっては、エラーを常に回避できるとは限りません。

    >


    1. SQLAlchemyのPostgreSQLJSONB実装にカスタムJSONエンコーダーを使用する

    2. SQL Server:NEWID()は常に一意のIDを提供しますか?

    3. 多次元OLAPCUBEとは何ですか?3次元以上のキューブの例を示します

    4. Excelの日付番号をOracleの日付に変更します