Oracle
 sql >> Base de données >  >> RDS >> Oracle

ORA-01873 :la précision leader

L'un de vos nombres numériques "epoch" semble être trop grand (ou trop petit) pour le numtodsinterval() fonction à gérer. La plus grande valeur que vous pouvez transmettre comme nombre de secondes est 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.

En tant qu'époque, le nombre maximal de secondes autorisé représente 2038-01-19 03:14:07. C'est le problème de l'année 2038 , essentiellement.

Vous pouvez aussi y arriver avec un nombre négatif :

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

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

Utilisation de -power(2, 31) passe à une valeur positive, mais tout ce qui est inférieur à cette erreur :

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

Vous divisez par 1000, donc l'une de vos colonnes F à K a une valeur qui dépasse 2147483647000. Cela devrait être assez facile à trouver, et vous voudrez peut-être envisager d'ajouter une contrainte de vérification à ces colonnes afin qu'elles ne puissent pas être définies trop high - vérifiez que la valeur de la colonne est inférieure ou égale à 1000 * (power(2, 31) - 1) . Et soit supérieur à zéro, soit supérieur à -1000 * (power(2, 31) aussi.

La raison pour laquelle il n'y a pas d'erreur lorsque vous avez un filtre comme where Col1 = 123 est que votre filtre (prédicat) est poussé vers le haut dans la requête de vue et que la ou les lignes avec des valeurs trop élevées ne sont pas évaluées. Peut-être n'avez-vous qu'une seule valeur de ce type, et son col1 la valeur n'est pas 123 et son col2 la valeur n'est pas 'xyz'. Si vous identifiez une ligne de problème et que vous filtrez en utilisant son col1 réel valeur, il y aura toujours une erreur. Sans filtre, l'évaluation est effectuée pour toutes les lignes.

Le nombre négatif spécifique que vous avez semble être un nombre magique :

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

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

Si vous souhaitez exclure cela, vous devrez modifier la définition de la vue pour ajouter un filtre, par exemple :

...
AND tab2.colh > 0

ou modifiez l'expression de la colonne pour la gérer, soit en la ignorant et en la laissant nulle, soit probablement plus utilement en renvoyant cette date magique :

    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,

Vous pouvez également passer d'un intervalle à une arithmétique de date :

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

Vous devrez cependant modifier la définition de la vue plutôt que votre requête, à moins que colh est inclus dans la liste de sélection (ce qui ne semble pas être le cas), et même si c'était le cas, vous ne pourriez que l'exclure - et cela n'éviterait pas toujours l'erreur, selon la façon dont l'optimiseur a traité la requête.