Oracle
 sql >> Database >  >> RDS >> Oracle

ORA-01873:la massima precisione

Uno dei tuoi numeri "epoca" numerici sembra essere troppo grande (o troppo piccolo) per numtodsinterval() funzione da gestire. Il valore più grande che puoi trasmettere come numero di secondi è 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.

Come epoca, il numero massimo consentito di secondi rappresenta 2038-01-19 03:14:07. Questo è il problema dell'anno 2038 , essenzialmente.

Ci puoi arrivare anche con un numero 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) esegue il wrapping su un valore positivo, ma qualcosa di inferiore a quell'errore:

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

Stai dividendo per 1000, quindi una delle tue colonne da F a K ha un valore che supera 2147483647000. Dovrebbe essere abbastanza facile da trovare e potresti prendere in considerazione l'aggiunta di un vincolo di controllo a quelle colonne in modo che non possano essere impostate anche loro alto - controlla che il valore della colonna sia minore o uguale a 1000 * (power(2, 31) - 1) . E maggiore di zero o maggiore di-1000 * (power(2, 31) anche.

Il motivo per cui non si verifica un errore quando si dispone di un filtro come where Col1 = 123 è che il tuo filtro (predicato) viene inserito nella query di visualizzazione e le righe con valori troppo alti non vengono valutate. Forse hai un solo valore di questo tipo e il suo col1 il valore è non 123 e relativo col2 il valore è non 'xyz'. Se identifichi una riga di problema e la filtri utilizzando il suo effettivo col1 valore sarà ancora errore. Senza filtri la valutazione viene eseguita per tutte le righe.

Il numero negativo specifico che hai sembra essere un numero magico:

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

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

Se vuoi escluderlo, dovresti modificare la definizione della vista per aggiungere un filtro, ad esempio:

...
AND tab2.colh > 0

o cambia l'espressione della colonna per gestirla, ignorandola e lasciandola nulla, o probabilmente restituendo più utilmente quella data magica:

    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,

Puoi anche passare dall'utilizzo di un intervallo all'utilizzo dell'aritmetica della data:

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

Tuttavia, dovrai modificare la definizione della vista piuttosto che la tua query, a meno che colh è incluso nell'elenco di selezione (cosa che non sembra essere) e, anche se lo fosse, potresti solo escluderlo e ciò potrebbe non evitare sempre l'errore, a seconda di come l'ottimizzatore ha gestito la query.