Et af dine numeriske 'epoke'-tal ser ud til at være for stort (eller for lille) til numtodsinterval()
funktion at håndtere. Den største værdi, du kan sende, da antallet af sekunder er 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 epoke repræsenterer det højest tilladte antal sekunder 2038-01-19 03:14:07. Dette er 2038-problemet i det væsentlige.
Du kan også komme dertil med et negativt tal:
SQL> select numtodsinterval(-2208988800, 'SECOND') as interval from dual;
SQL Error: ORA-01873: the leading precision of the interval is too small
Brug af -power(2, 31)
ombrydes til en positiv værdi, men alt lavere end det fejler:
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 dividerer med 1000, så en af dine kolonner F til K har en værdi, der overstiger 2147483647000. Det burde være ret nemt at finde, og du vil måske overveje at tilføje en kontrolbegrænsning til disse kolonner, så de ikke også kan indstilles høj - kontroller, at kolonneværdien er mindre end eller lig med 1000 * (power(2, 31) - 1)
. Og enten større end nul eller større end-1000 * (power(2, 31)
også.
Grunden til at det ikke fejler, når du har et filter som where Col1 = 123
er, at dit filter (prædikat) er skubbet op i view-forespørgslen, og rækken/rækkerne med værdier, der er for høje, bliver ikke evalueret. Måske har du kun en enkelt sådan værdi, og dens col1
værdien er ikke 123 og dens col2
værdien er ikke 'xyz'. Hvis du identificerer en problemrække og filter ved hjælp af dens faktiske col1
værdi det vil stadig fejle. Uden filtre udføres evalueringen for alle rækker.
Det specifikke negative tal, du har, ser ud til at være et magisk tal:
SQL> select date '1970-01-01' - 2208988800/86400 from dual;
DATE'1970-01-01'-2208988800/86400
---------------------------------
1900-01-01 00:00:00
Hvis du vil udelukke det, skal du ændre visningsdefinitionen til enten at tilføje et filter, f.eks.:
...
AND tab2.colh > 0
eller skift kolonneudtrykket for at håndtere det, enten ved at rignorere det og lade det være nul, eller sandsynligvis mere nyttigt returnere den magiske dato:
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 også skifte fra at bruge et interval til at bruge dato-aritmetik:
TO_CHAR(DATE'1970-01-01' + ( tab2.colh / 86400000 ), 'YYYY/MM/DD HH24:MI:SS') AS Col13,
Du bliver dog nødt til at ændre visningsdefinitionen i stedet for din forespørgsel, medmindre colh
er inkluderet i udvælgelseslisten (hvilket det ikke ser ud til at være), og selvom det var, kunne du kun udelukke det - og det kan stadig ikke altid undgå fejlen, afhængigt af hvordan optimeringsværktøjet håndterede forespørgslen.