sql >> Databasteknik >  >> RDS >> Oracle

Oracle 2 bindestreck i nummerkolumnen?

Det betyder ingenting, och det är inte "för" någonting; din data är korrupt, är jag rädd. -- är ett verkligt värde från din tabell, men det är inte ett tal. Oracles interna representation för nummer täcks av not 1031902.6 om du har tillgång till det, eller denna förklarar det om du inte gör det . Om det verkligen var ett negativt tal så borde den sista hexadecimala byten vara 66. Dumpning av talet det verkar vara - med ett enda minustecken, inte två, vilket är meningslöst - ger:

select dump(-1331013400000000000000000000, 1016) from dual;

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

Att skapa ogiltiga nummer i Oracle är inte enkelt (jag antar att du inte skulle förvänta dig att det skulle vara det), men det här är en metod som jag har använt tidigare. En av ledtrådarna, förutom det dubbla minustecknet och att de alla är lika långa, är att omvandling av det dumpade värdet tillbaka till ett tal inte ger samma resultat:

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

Det här är från Oracle 9i, de stänger jag har nu till en 8i-databas, så resultaten kan variera lite.

Att inte kunna göra to_number(value) är en stor ledtråd också förstås; det finns en implicit to_char() när du gör det så försöker den konvertera textrepresentationen till ett tal, vilket förklarar felet. to_char() värdet stämmer inte överens med vad ett enkelt urval gör heller, intressant nog. Du skulle se samma fel om du gjorde det med din data.

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

Om du inte vet var den dåliga informationen kom ifrån och har originalet kvar, kan du förmodligen inte rädda dessa värden. Jag tror att det bästa du kan göra är att ignorera det, eller ersätta det med något som kommer att migrera - om fältet är nullbart så null skulle vara det säkra alternativet, annars antar jag att du måste välja ett magiskt värde.

Identifiering och modifiering av de berörda raderna kan göras via en funktion; möjligen något i stil med:

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

Med samma ogiltiga värde skapat tidigare och ett giltigt värde:

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

Inte perfekt på något sätt, men vid det här laget tror jag att du bara räddar det du kan. Du kan ta bort raderna istället för att uppdatera dem, eller ställa in värdet på något annat, det beror på hur du vill gå vidare.

Du kan försöka involvera Oracle för att se om de kan ta reda på vad som hände och se om de har några knep för att komma tillbaka till de ursprungliga värdena - vilket verkar osannolikt - men jag är inte säker på att du skulle få mycket stöd för en så gammal version av databasen.

Naturligtvis, utan att veta hur och när korruptionen introducerades (via en tvivelaktig import kanske, eller via ett buggigt OCI-program), måste du ifrågasätta giltigheten av alla andra data, både i den kolumnen och på andra ställen. I det här fallet ser korruptionen väldigt enhetlig ut - alla ogiltiga värden verkar vara konstruerade på samma sätt - så du kan vara OK. Men generellt sett kan något som sätter in felaktiga bytes i ett internt värde få ett felaktigt, men fortfarande giltigt, värde. Det kan se ut ungefär som det ska, eller så kan det vara storleksordningar från det ursprungliga förväntade värdet, och det finns egentligen inget sätt att säga.




  1. Vänster Gå med i en enda slumpmässig inspelning MySQL

  2. .NET, C#, LINQ, SQL och OR-Mapping - jag förstår det bara inte :(

  3. MySQL INSERT om det inte finns (använder inte primärnyckel)

  4. Att infoga värden i en mysql-databas fungerar inte som förväntat