数字列中的Oracle 2连字符?

Posted

技术标签:

【中文标题】数字列中的Oracle 2连字符?【英文标题】:Oracle 2 hyphens in number column? 【发布时间】:2013-11-29 01:24:31 【问题描述】:

我有一个需要迁移到 sql server 的 Oracle 表(版本 8i),其中一列是 NUMBER 数据类型。在其中,它的值如下:

--1331013400000000000000000000
--1331017903617177360300000000
--1331012863048235233700000000

其中

0.9574875526618150
2.51572327044025

-- 看起来像存储在数字列中的实际值。我不明白破折号的用途或它们的含义,但是,当我尝试通过 ssma 迁移数据时,我得到“无法将字符串值放入浮点数”,因此很明显 sql server 在这种情况下绊倒了,因为我愿意。

我确信我可以找到一种方法来处理这些奇怪的数据,我只是想知道这到底意味着什么以及它的用途,我在 Google 上搜索过,但令人惊讶的是空手而归。有人知道吗?

转储 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

更新:

这是统计计算库中的错误。在某些情况下,返回 Doubles 的函数在计算 sdev 时使用 sqrt 会生成 NaN 值。准备好的语句构造中使用的 Oracle 驱动程序 (oracle14.zip) 不会验证数据,而是发送和写入原始字节,这最终导致了损坏。有趣的是,当我尝试在 prep 语句中设置一个 NaN 值时,MS SQL Server 驱动程序不允许我进行准备语句并引发异常。将其发布为“仅供参考”...

【问题讨论】:

你用什么工具/命令来得到这个输出? 我们都知道不存在以-开头的数字。因此,这些值不可能存储在 NUMBER 字段中。正如 Arturo Hernandez 建议的那样,这只是一种展示方式。 sql server 迁移助手在 oracle 中标记为数字的字段上绊倒,可转换为 sql server 中的浮点数,当我查询表时出现错误消息“无法将字符串放入浮点数”,我看到了结果.我还做了结构和数据的 sql 转储,所以不是显示的东西。奇怪的部分,当我尝试重新插入具有相似值的行时,我得到 [Err] ORA-01722: invalid number 如果这确实是一个数字列,那么数据看起来已经损坏 - 它是如何插入的?您可以为这些行添加来自dump(<column>, 1016) 的内部表示吗? 【参考方案1】:

它没有任何意义,也不是“为了”任何东西;恐怕您的数据已损坏。 -- 是表中的实际值,但不是数字。如果您有权访问 Oracle 的内部数字表示形式,请参见注释 1031902.6,或 this explains it if you don't。如果它真的是一个负数,那么最后一个十六进制字节应该是 66。转储它看起来是的数字 - 用一个减号,而不是两个,这是没有意义的 - 给出:

select dump(-1331013400000000000000000000, 1016) from dual;

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

在 Oracle 中创建无效数字并不简单(我想你不会这么想的),但这是我以前使用过的一种方法。除了双减号并且它们的长度都相同之外,其中一条线索是将转储的值转换回数字并不会给出相同的结果:

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

这是来自 Oracle 9i,我现在关闭了一个 8i 数据库,因此结果可能会有所不同。

当然不能to_number(value)也是大线索;当你这样做时有一个隐含的to_char(),所以它试图将文本表示转换为一个数字,这解释了错误。有趣的是,to_char() 的值也不匹配简单的选择。如果您对数据执行此操作,您会看到相同的错误。

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

除非您知道坏数据的来源并保留原始数据,否则您可能无法挽救这些值。我认为你能做的最好的就是忽略它,或者用可以迁移的东西替换它 - 如果该字段可以为空,那么 null 将是安全的选择,否则我猜你必须选择一个神奇的值。

识别和修改受影响的行可以通过一个函数来完成;可能是这样的:

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

使用之前创建的相同无效值和一个有效值:

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

无论如何都不理想,但在这一点上,我认为你只是在挽救你所能做的。您可以删除行而不是更新它们,或者将值设置为其他值,这取决于您要如何进行。

您可以尝试让 Oracle 参与进来,看看他们是否可以弄清楚发生了什么,看看他们是否有任何技巧可以恢复到原始值 - 这似乎不太可能 - 但我不确定你会得到很多对这种旧版本数据库的支持。

当然,在不知道如何以及何时引入损坏的情况下(可能是通过狡猾的导入,或通过错误的 OCI 程序),您必须质疑该列和其他地方的所有其他数据的有效性。在这种情况下,损坏看起来非常一致 - 所有无效值似乎都是以相同的方式构造的 - 所以你可能没问题。不过,通常情况下,将不正确的字节放入内部值可能会侥幸获得错误但仍然有效的值。它可能看起来是正确的,也可能与最初的期望值相差几个数量级,而且真的无法判断。

【讨论】:

非常感谢,真的很有帮助。我玩过你的函数,使用 convert_raw_value 插入数字,似乎以 '32ea' 开头的值会导致损坏。有趣的是,ea00 产生巨大的数字 -100000000000000000000000000000000000000000000000000000000000000000000000000000000000

以上是关于数字列中的Oracle 2连字符?的主要内容,如果未能解决你的问题,请参考以下文章

oracle怎么在数字列中添加空格

Oracle:一个查询,它计算字符串中所有非字母数字字符的出现次数

Oracle同一列中存放数字或字母时的排序

用数字R替换列中的字符

如何从 Python 的数据框列中的字符串中删除非字母数字字符?

从oracle中的数字确定月份(书面)