Oracle 2 hyphens in number column?

妖精的绣舞 提交于 2019-12-24 00:41:31

问题


I have an Oracle table (version 8i) which I need to migrate to sql server, one of the columns is a NUMBER datatype. In it, it has values like so:

--1331013400000000000000000000
--1331017903617177360300000000
--1331012863048235233700000000

among others

0.9574875526618150
2.51572327044025

The -- look like actual values stored in number column. I don't understand what the dash dash are for or what they mean, however, when I try to migrate data via ssma, i get "can't put string value into a float" so clearly sql server stumbles over this case, as I do.

I'm sure I can figure out a way to deal with this weird data, I'm just wondering what heck this means and what it's for, I Googled but surprisingly came out empty handed. Anyone have any clue?

dump 1016:

 0.2722718362012630 Typ=2 Len=9: c0,1c,17,48,54,3f,2,1b,1f
 --1331013400000000000000000000 Typ=2 Len=4: 32,ea,0,43
 0.50761421319797   Typ=2 Len=8: c0,33,4d,f,16,20,62,62
 1  Typ=2 Len=2: c1,2
 0.9574875526618150 Typ=2 Len=9: c0,60,4b,58,38,1b,3e,52,33
 1.11894371713103   Typ=2 Len=9: c1,2,c,5a,2c,48,48,20,4
 2.51572327044025   Typ=2 Len=9: c1,3,34,3a,18,1c,5,29,1a
 0.0537258905066351 Typ=2 Len=9: c0,6,26,1a,5a,6,7,40,34
 0.1851303317535540 Typ=2 Len=9: c0,13,34,1f,22,12,36,38,29
 0.0000000000000000000000000000306386   Typ=2 Len=4: b2,1f,40,57
 1.6164 Typ=2 Len=4: c1,2,3e,41
 0.1289839930864580 Typ=2 Len=9: c0,d,5a,54,64,1f,57,2e,51
 0.004721435316336170   Typ=2 Len=9: bf,30,16,2c,36,11,22,3e,47
 --1331017903617177360300000000 Typ=2 Len=10: 32,ea,0,16,62,28,1e,18,41,62
 --1331012863048235233700000000 Typ=2 Len=10: 32,ea,0,49,26,61,13,42,4e,40
 --1331010715609612880500000000 Typ=2 Len=10: 32,ea,0,5e,56,29,5,59,d,60
 0.0778391842453491 Typ=2 Len=9: c0,8,4f,28,13,2b,2e,23,5c
 --1331010187793684447000000000 Typ=2 Len=10: 32,ea,0,64,e,16,41,11,39,1f
 0.8296 Typ=2 Len=3: c0,53,61
 --1331015225486314961400000000 Typ=2 Len=10: 32,ea,0,31,4c,35,26,57,5,57
 --1331016035469906437500000000 Typ=2 Len=10: 32,ea,0,29,42,37,2,5f,3a,1a
 0.3301637612255680 Typ=2 Len=9: c0,22,2,40,4d,d,1a,39,51
 0.2666453350398630 Typ=2 Len=9: c0,1b,43,2e,22,33,28,57,1f
 0.1581527755812110 Typ=2 Len=9: c0,10,52,35,4e,38,52,16,b
 0.8089305937550560 Typ=2 Len=9: c0,51,5a,1f,3c,26,38,6,3d
 --1331015006297067350000000000 Typ=2 Len=9: 32,ea,0,33,5f,48,1f,22,42
 0.3745318352059930 Typ=2 Len=9: c0,26,2e,20,54,35,6,64,1f
 --1331017625157985988000000000 Typ=2 Len=10: 32,ea,0,19,4c,56,16,10,3,15

Update:

It was a bug in a statistics calc library. Under certain conditions a function returning Doubles generated a NaN value when taking sqrt while calculation sdev. Oracle driver (oracle14.zip) used in prepared statement construction does not validate data, but sends and writes raw bytes, which is what ended up causing the corruption. Interestingly enough, MS SQL Server driver did not let me make a prepared statement and threw an exception when i tried to set a value that was a NaN in a prep statement. Posting this just as "fyi"...


回答1:


It doesn't mean anything, and it isn't 'for' anything; your data is corrupt, I'm afraid. The -- is an actual value from your table, but it isn't a number. Oracle's internal representation for numbers is covered in note 1031902.6 if you have access to that, or this explains it if you don't. If it was really a negative number then the last hexadecimal byte should be 66. Dumping the number it appears to be - with a single minus sign, not two, which is meaningless - gives:

select dump(-1331013400000000000000000000, 1016) from dual;

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

Creating invalid numbers in Oracle isn't straightforward (I suppose you wouldn't expect it to be), but this is a method I've used before. One of the clues, apart from the double minus sign and that they are all the same length, is that converting the dumped value back into a number doesn't give the same result:

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

This is from Oracle 9i, the closes I have now to an 8i database, so the results may vary a little.

Not being able to do to_number(value) is big clue too of course; there's an implicit to_char() when you do that so it's trying to convert the text representation to a number, which explains the error. The to_char() value doesn't match what a simple select does either, interestingly. You'd see the same error if you did that with your 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

Unless you know where the bad data came from and have the original still, you probably can't salvage these values. I think the best you can do is ignore it, or replace it with something that will migrate - if the field is nullable then null would be the safe option, otherwise I guess you'd have to pick a magic value.

Identifying and modifying the affected rows can be done via a function; possibly something like:

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

With the same invalid value created earlier and one valid value:

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

Not ideal by any means, but at this point I think you're just salvaging what you can. You could delete the rows rather than updating them, or set the value to something else, it depends how you want to proceed.

You could try to get Oracle involved to see if they can figure out what happened and see if they have any tricks to get back to the original values - which seems unlikely - but I'm not sure you'd get a lot of support for such an old version of the database.

Of course, without knowing how and when the corruption was introduced (via a dodgy import perhaps, or via a buggy OCI program), you have to question the validity of all the other data, both in that column and elsewhere. In this case the corruption looks very uniform - all the invalid values seem to be constructed the same way - so you may be OK. Generally though, something that puts incorrect bytes into an internal value could fluke a wrong, but still valid, value. It could look about right, or it could be orders of magnitude out from the original expected value, and there's really no way to tell.



来源:https://stackoverflow.com/questions/20004679/oracle-2-hyphens-in-number-column

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!