Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

ORA-01873:a precisão líder


Um de seus números numéricos de 'época' parece ser muito grande (ou muito pequeno) para o numtodsinterval() função de manusear. O maior valor que você pode passar como número de segundos é 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.

Como uma época, o maior número permitido de segundos representa 2038-01-19 03:14:07. Este é o problema do ano de 2038 , essencialmente.

Você também pode chegar lá com um número 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) quebra para um valor positivo, mas qualquer coisa menor que esses erros:
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

Você está dividindo por 1000, então uma de suas colunas F a K tem um valor que excede 2147483647000. Isso deve ser bastante fácil de encontrar, e você pode considerar adicionar uma restrição de verificação a essas colunas para que elas não possam ser definidas também high - verifique se o valor da coluna é menor ou igual a 1000 * (power(2, 31) - 1) . E maior que zero, ou maior que-1000 * (power(2, 31) também.

O motivo pelo qual não ocorre erro quando você tem um filtro como where Col1 = 123 é que seu filtro (predicado) é enviado para a consulta de visualização e as linhas com valores muito altos não são avaliadas. Talvez você tenha apenas um único valor, e seu col1 o valor é não 123 e seu col2 o valor é não 'xyz'. Se você identificar uma linha com problema e filtrar usando seu col1 real valor ele ainda vai dar erro. Sem filtros, a avaliação é feita para todas as linhas.

O número negativo específico que você tem parece ser um número mágico:
SQL> select date '1970-01-01' - 2208988800/86400 from dual;

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

Se você quiser excluir isso, deverá modificar a definição da visualização para adicionar um filtro, por exemplo:
...
AND tab2.colh > 0

ou altere a expressão da coluna para lidar com isso, ignorando-a e deixando-a nula, ou provavelmente retornando mais útil essa data mágica:
    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,

Você também pode mudar de usar um intervalo para usar aritmética de data:
    TO_CHAR(DATE'1970-01-01' + ( tab2.colh / 86400000 ), 'YYYY/MM/DD HH24:MI:SS') AS Col13,

Você terá que modificar a definição de visualização em vez de sua consulta, a menos que colh está incluído na lista de seleção (o que não parece ser), e mesmo que estivesse, você só poderia excluí-lo - e isso ainda pode nem sempre evitar o erro, dependendo de como o otimizador tratou a consulta.