sql >> Base de Datos >  >> RDS >> Oracle

ORA-01873:la precisión líder

Uno de sus números numéricos de 'época' parece ser demasiado grande (o demasiado pequeño) para el numtodsinterval() función a manejar. El mayor valor que puede pasar como número de segundos es 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.

Como época, el mayor número permitido de segundos representa 2038-01-19 03:14:07. Este es el problema del año 2038 , esencialmente.

También puede llegar allí con un número negativo:

SQL> select numtodsinterval(-2208988800, 'SECOND') as interval from dual;

SQL Error: ORA-01873: the leading precision of the interval is too small

Usando -power(2, 31) se ajusta a un valor positivo, pero cualquier valor inferior a ese genera errores:

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

Está dividiendo por 1000, por lo que una de sus columnas F a K tiene un valor que excede 2147483647000. Eso debería ser bastante fácil de encontrar, y es posible que desee considerar agregar una restricción de verificación a esas columnas para que no se puedan configurar también alto:verifique que el valor de la columna sea menor o igual a 1000 * (power(2, 31) - 1) . Y mayor que cero, o mayor que-1000 * (power(2, 31) también.

La razón por la que no da error cuando tienes un filtro como where Col1 = 123 es que su filtro (predicado) se empuja hacia arriba en la consulta de vista y las filas con valores que son demasiado altos no se evalúan. Tal vez solo tenga uno de esos valores y sea col1 el valor es no 123 y su col2 el valor es no 'xyz'. Si identifica una fila problemática y filtra usando su col1 real valor todavía será error. Sin filtros, la evaluación se realiza para todas las filas.

El número negativo específico que tienes parece ser un número mágico:

SQL> select date '1970-01-01' - 2208988800/86400 from dual;

DATE'1970-01-01'-2208988800/86400
---------------------------------
1900-01-01 00:00:00              

Si desea excluir eso, tendría que modificar la definición de vista para agregar un filtro, por ejemplo:

...
AND tab2.colh > 0

o cambie la expresión de la columna para manejarla, ya sea ignorándola y dejándola nula, o probablemente sea más útil devolver esa fecha mágica:

    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,

También puede cambiar de usar un intervalo a usar aritmética de fechas:

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

Sin embargo, tendrá que modificar la definición de la vista en lugar de su consulta, a menos que colh está incluido en la lista de selección (que no parece estarlo), e incluso si lo estuviera, solo podría excluirlo, y eso podría no siempre evitar el error, dependiendo de cómo el optimizador manejó la consulta.