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

I trattini di Oracle 2 nella colonna dei numeri?

Non significa nulla e non è "per" nulla; i tuoi dati sono corrotti, temo. Il -- è un valore effettivo dalla tua tabella, ma non è un numero. La rappresentazione interna di Oracle per i numeri è trattata nella nota 1031902.6 se hai accesso a quella, o questo lo spiega se non lo fai . Se fosse davvero un numero negativo, l'ultimo byte esadecimale dovrebbe essere 66. Scaricando il numero che sembra essere - con un solo segno meno, non due, il che non ha significato - si ottiene:

select dump(-1331013400000000000000000000, 1016) from dual;

DUMP(-1331013400000000000000000000,1016)
----------------------------------------
Typ=2 Len=6: 31,58,46,64,43,66           

La creazione di numeri non validi in Oracle non è semplice (suppongo che non ti aspetteresti che lo fosse), ma questo è un metodo che ho usato prima. Uno degli indizi, a parte il doppio segno meno e che sono tutti della stessa lunghezza, è che riconvertire il valore scaricato in un numero non dà lo stesso risultato:

create table t42(value number);

declare
  n number;
begin
  dbms_stats.convert_raw_value('32ea004366', n);
  insert into t42 (value) values (n);
end;
/

select value from t42;

                                 VALUE
--------------------------------------
           -<3:13400000000000000000000

Questo proviene da Oracle 9i, le chiusure che ho ora a un database 8i, quindi i risultati possono variare leggermente.

Non essere in grado di eseguire to_number(value) è anche un grande indizio ovviamente; c'è un implicito to_char() quando lo fai, sta cercando di convertire la rappresentazione del testo in un numero, il che spiega l'errore. Il to_char() il valore non corrisponde nemmeno a ciò che fa una semplice selezione, è interessante notare. Vedresti lo stesso errore se lo facessi con i tuoi dati.

select to_number(value) from t42;
select to_number(value) from t42
                 *
ERROR at line 1:
ORA-01722: invalid number

select to_char(value) from t42;

TO_CHAR(VALUE)
----------------------------------------
-`003400000000000000000000

A meno che tu non sappia da dove provengono i dati errati e non hai ancora l'originale, probabilmente non puoi salvare questi valori. Penso che il meglio che puoi fare sia ignorarlo o sostituirlo con qualcosa che migrerà - se il campo è annullabile, allora null sarebbe l'opzione sicura, altrimenti immagino che dovresti scegliere un valore magico.

L'identificazione e la modifica delle righe interessate possono essere eseguite tramite una funzione; possibilmente qualcosa come:

create or replace function null_bad_number(value number)
return number deterministic as
  tmp_value number;
  invalid_number exception;
  pragma exception_init(invalid_number, -1722);
begin
  select to_number(value) into tmp_value from dual;
  return value;
exception
  when invalid_number then
    return null;
end;
/

Con lo stesso valore non valido creato in precedenza e un valore valido:

insert into t42 (value) values (0.9574875526618150);

select * from t42;

     VALUE
----------
-`.003E+24
.957487553

update t42 set value = null
where value is not null
and null_bad_number(value) is null;

1 row updated.

select * from t42;

     VALUE
----------

.957487553

Non è l'ideale in alcun modo, ma a questo punto penso che stai solo salvando quello che puoi. Potresti eliminare le righe anziché aggiornarle, oppure impostare il valore su qualcos'altro, dipende da come vuoi procedere.

Potresti provare a coinvolgere Oracle per vedere se riescono a capire cosa è successo e vedere se hanno qualche trucco per tornare ai valori originali - il che sembra improbabile - ma non sono sicuro che otterresti molto supporto per una versione così vecchia del database.

Naturalmente, senza sapere come e quando è stata introdotta la corruzione (forse tramite un'importazione dubbia, o tramite un programma OCI buggato), devi mettere in dubbio la validità di tutti gli altri dati, sia in quella colonna che altrove. In questo caso la corruzione sembra molto uniforme - tutti i valori non validi sembrano essere costruiti allo stesso modo - quindi potresti essere a posto. In genere, tuttavia, qualcosa che inserisce byte errati in un valore interno potrebbe generare un valore errato, ma comunque valido. Potrebbe sembrare giusto, oppure potrebbero essere ordini di grandezza fuori dal valore previsto originale e non c'è davvero modo di dirlo.