Oracle
 sql >> Base de données >  >> RDS >> Oracle

Oracle 2 traits d'union dans la colonne des nombres ?

Cela ne veut rien dire, et ce n'est « pour » rien; vos données sont corrompues, j'en ai peur. Le -- est une valeur réelle de votre table, mais ce n'est pas un nombre. La représentation interne d'Oracle pour les nombres est couverte dans la note 1031902.6 si vous y avez accès, ou ceci explique-le si ce n'est pas le cas . S'il s'agissait vraiment d'un nombre négatif, le dernier octet hexadécimal devrait être 66. Le vidage du nombre qu'il semble être - avec un seul signe moins, et non deux, ce qui n'a pas de sens - donne :

select dump(-1331013400000000000000000000, 1016) from dual;

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

Créer des nombres invalides dans Oracle n'est pas simple (je suppose que vous ne vous y attendriez pas), mais c'est une méthode que j'ai déjà utilisée. L'un des indices, mis à part le double signe moins et qu'ils ont tous la même longueur, est que reconvertir la valeur déchargée en un nombre ne donne pas le même résultat :

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

Cela vient d'Oracle 9i, la fermeture que j'ai maintenant d'une base de données 8i, donc les résultats peuvent varier un peu.

Ne pas pouvoir faire to_number(value) est un gros indice aussi bien sûr; il y a un to_char() implicite lorsque vous faites cela, il essaie de convertir la représentation textuelle en nombre, ce qui explique l'erreur. Le to_char() la valeur ne correspond pas non plus à ce qu'une simple sélection fait, ce qui est intéressant. Vous verriez la même erreur si vous faisiez cela avec vos données.

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

À moins que vous ne sachiez d'où viennent les mauvaises données et que vous ayez toujours l'original, vous ne pourrez probablement pas récupérer ces valeurs. Je pense que le mieux que vous puissiez faire est de l'ignorer ou de le remplacer par quelque chose qui migrera - si le champ est nullable alors null serait l'option sûre, sinon je suppose que vous devriez choisir une valeur magique.

L'identification et la modification des lignes concernées peuvent se faire via une fonction ; peut-être quelque chose comme :

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;
/

Avec la même valeur invalide créée précédemment et une valeur valide :

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

Ce n'est en aucun cas idéal, mais à ce stade, je pense que vous ne faites que récupérer ce que vous pouvez. Vous pouvez supprimer les lignes plutôt que de les mettre à jour, ou définir la valeur sur autre chose, cela dépend de la façon dont vous souhaitez procéder.

Vous pouvez essayer d'impliquer Oracle pour voir s'ils peuvent comprendre ce qui s'est passé et voir s'ils ont des astuces pour revenir aux valeurs d'origine - ce qui semble peu probable - mais je ne suis pas sûr que vous obtiendriez beaucoup de soutien pour une si ancienne version de la base de données.

Bien sûr, sans savoir comment et quand la corruption a été introduite (via une importation douteuse peut-être, ou via un programme OCI bogué), vous devez remettre en question la validité de toutes les autres données, à la fois dans cette colonne et ailleurs. Dans ce cas, la corruption semble très uniforme - toutes les valeurs invalides semblent être construites de la même manière - donc tout va bien. En règle générale, cependant, quelque chose qui met des octets incorrects dans une valeur interne peut donner une valeur erronée, mais toujours valide. Cela peut sembler correct, ou il peut s'agir d'ordres de grandeur par rapport à la valeur attendue d'origine, et il n'y a vraiment aucun moyen de le savoir.