sql >> Database >  >> RDS >> Oracle

ORA-01873:de toonaangevende precisie

Een van uw numerieke 'epoch'-nummers lijkt te groot (of te klein) te zijn voor de numtodsinterval() functie te hanteren. De grootste waarde die u kunt doorgeven als het aantal seconden is 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.

Als een tijdperk vertegenwoordigt dat hoogst toegestane aantal seconden 2038-01-19 03:14:07. Dit is het probleem van het jaar 2038 , in wezen.

Je kunt er ook komen met een negatief getal:

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) gebruiken loopt terug naar een positieve waarde, maar alles lager dan dat geeft fouten:

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

Je deelt door 1000, dus een van je kolommen F tot K heeft een waarde die groter is dan 2147483647000. Dat zou vrij gemakkelijk te vinden moeten zijn, en je zou kunnen overwegen om een ​​controlebeperking aan die kolommen toe te voegen, zodat ze niet ook kunnen worden ingesteld hoog - controleer of de kolomwaarde kleiner is dan of gelijk is aan 1000 * (power(2, 31) - 1) . En groter dan nul, of groter dan-1000 * (power(2, 31) ook.

De reden waarom het geen fout geeft als je een filter hebt zoals where Col1 = 123 is dat uw filter (predikaat) omhoog wordt geduwd in de view-query en dat de rij(en) met te hoge waarden niet worden geëvalueerd. Misschien heb je maar één zo'n waarde, en zijn col1 waarde is niet 123 en zijn col2 waarde is niet 'xyz'. Als u een probleemrij identificeert en filtert met behulp van de werkelijke col1 waarde zal het nog steeds fout. Zonder filters wordt de evaluatie gedaan voor alle rijen.

Het specifieke negatieve getal dat je hebt, lijkt een magisch getal te zijn:

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

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

Als u dat wilt uitsluiten, moet u de weergavedefinitie wijzigen om een ​​filter toe te voegen, bijvoorbeeld:

...
AND tab2.colh > 0

of verander de kolomuitdrukking om het te verwerken, ofwel door het te negeren en het null te laten, of waarschijnlijk nuttiger die magische datum terug te geven:

    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,

U kunt ook overschakelen van het gebruik van een interval naar het gebruik van datumberekeningen:

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

U moet echter de weergavedefinitie wijzigen in plaats van uw zoekopdracht, tenzij colh is opgenomen in de selectielijst (wat het niet lijkt te zijn), en zelfs als dat zo was, zou je het alleen kunnen uitsluiten - en dat kan de fout nog steeds niet altijd voorkomen, afhankelijk van hoe de optimiser de zoekopdracht heeft afgehandeld.




  1. CTE retourneert fout

  2. Resultatentabel converteren naar JSON-array in MySQL

  3. UTL_FILE.FOPEN() procedure accepteert pad voor directory niet?

  4. Selecteer rijen met in het bijzonder bereik sql-query