sql >> Databasteknik >  >> RDS >> Oracle

ORA-01873:den ledande precisionen

Ett av dina numeriska 'epok'-nummer verkar vara för stort (eller för litet) för numtodsinterval() funktion att hantera. Det största värdet du kan skicka eftersom antalet sekunder är 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.

Som en epok representerar det högsta tillåtna antalet sekunder 2038-01-19 03:14:07. Detta är 2038 års problem i huvudsak.

Du kan också komma dit med ett negativt tal:

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

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

Använder -power(2, 31) radbryts till ett positivt värde, men något lägre än det felar:

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

Du dividerar med 1000, så en av dina kolumner F till K har ett värde som överstiger 2147483647000. Det borde vara ganska lätt att hitta, och du kanske vill överväga att lägga till en kontrollbegränsning för dessa kolumner så att de inte kan ställas in också hög - kontrollera att kolumnvärdet är mindre än eller lika med 1000 * (power(2, 31) - 1) . Och antingen större än noll eller större än-1000 * (power(2, 31) också.

Anledningen till att det inte blir fel när du har ett filter som where Col1 = 123 är att ditt filter (predikat) trycks upp i vyfrågan och raden/raderna med värden som är för höga utvärderas inte. Du kanske bara har ett enda sådant värde och dess col1 värdet är inte 123 och dess col2 värdet är inte 'xyz'. Om du identifierar en problemrad och filtrerar med den faktiska col1 värde det kommer fortfarande att fel. Utan filter görs utvärderingen för alla rader.

Det specifika negativa talet du har verkar vara ett magiskt tal:

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

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

Om du vill utesluta det måste du ändra vydefinitionen för att antingen lägga till ett filter, t.ex.:

...
AND tab2.colh > 0

eller ändra kolumnuttrycket för att hantera det, antingen rignorera det och lämna det null, eller förmodligen mer användbart returnera det magiska datumet:

    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,

Du kan också ändra från att använda ett intervall till att använda datumaritmetik:

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

Du måste dock ändra vydefinitionen snarare än din fråga, om inte colh ingår i urvalslistan (vilket det inte verkar vara), och även om det var så kunde du bara utesluta det - och det kanske inte alltid undviker felet, beroende på hur optimeraren hanterade frågan.




  1. Postgresql create extension misslyckas

  2. Hur man infogar en ny rad i PostgreSQL

  3. Är ordningen på infogningen specificerad för INSERT IGNORE ... SELECT?

  4. sql (oracle) för att välja de första 10 posterna, sedan de nästa 10, och så vidare