2

如果有人将一列设为 VARCHAR2(256 CHAR) 并且该列中只有数字怎么办。我想得到最高的数字。问题是:数字大于 999999,但是 varchar 的 Max 总是给我一个 999999 的最大数字

我试过to_number(max(numbers), '9999999999999')了,但我还是得到了 999999,那不可能。有任何想法吗?谢谢

4

3 回答 3

7

最好的方法是

第一个解决方案 将列转换为数字

或者

第二种解决方案 将您查询中的数据转换为数字而不是获取数据...

例子

 select max(col1) from(
  select to_number(numbers) as col1 from table ) d

必须这样,因为如果您在 TO_NUMBER() 之前调用 MAX(),它将按字母顺序排序,然后 999999 大于 100000000000。请注意,将 TO_NUMBER() 应用于 varchar2 列会产生 INVALID_NUMBER 异常的风险,应该包含任何非数字字符的列。这就是为什么首选提出的第一个解决方案。

于 2012-05-30T09:26:18.040 回答
6

在 Oracle 中,NUMBER 类型包含基数为 100 的浮点值,其精度为 38 位有效数字,最大值为 9999...(38 9's) x 10^125。有两个问题 - 第一个是 NUMBER 是否可以包含从 256 字符串转换的值,第二个是是否可以区分两个在数字方面“接近”的值。

让我们从一个 256 个字符的字符串开始,并尝试将其转换为数字。显而易见的事情是:

SELECT TO_NUMBER('9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999') AS VAL
  FROM DUAL;

执行上面我们得到:

ORA-01426: numeric overflow

我们之前已经注意到了,这是我们预期的。NUMBER 可以处理的最大指数是 125 - 这里我们尝试转换具有 256 个有效数字的值。NUMBER 无法处理此问题。如果我们将位数减少到 125,如下所示:

SELECT TO_NUMBER('99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999') AS VAL
  FROM DUAL;

它工作正常,我们的答案是 1E125。

<眨眼>

哇!等待!!什么???答案是1 x 10^125???那些9的呢?!?!?!?

记得之前我提到过,Oracle NUMBER 是一个浮点值,最大精度为 38,最大指数为 125。从 TO_NUMBER 125 的角度来看,所有串在一起的 9 不能精确表示 - 数字太多(请记住,最大精度为 38(稍后会详细介绍))。所以它尽其所能 - 它转换前 38 位数字(全部为 9),然后说“我应该如何最好地舍入它以使结果 A)代表输入和 B)尽可能接近我能得到我得到的东西吗?”。在这种情况下,它查看数字 39,发现它是 9,并决定向上舍入。由于所有其他数字也是 9,因此它继续整齐地四舍五入,直到以 1 作为剩余尾数位结束。

* 稍后,回到牧场…… *

好的,之前我提到过 NUMBER 的精度为 38 位。这并不完全正确 - 它实际上可以区分高达 40 位精度的值,至少有时,如果风是正确的,并且你正在走下坡路。这是一个例子:

SELECT CASE
         WHEN to_number('9999999999999999999999999999999999999999') >
              to_number('9999999999999999999999999999999999999998')
           THEN 'Greater'
           ELSE 'Not greater'
       END AS VAL
  FROM DUAL;

这两个值各有 40 位(计数留给极度无聊的读者作为练习:-)。如果执行上述操作,您将返回'Greater',表明两个 40 位数值的比较成功。

现在找点乐子。如果您在每个字符串中添加一个额外的“9”,生成一个 41 位的值,然后重新执行该语句,它将返回“Not greater”。

<眨眼>

等待!什么??哇!!!这些价值观明显不同!即使是 TotalFool (tm) 也能看到!!

这里的问题是 41 位数字超过了 NUMBER 类型的精度,因此当 TO_NUMBER 发现它有这么长的值时,它开始丢弃右侧的数字。因此,即使这两个非常大的数字对你和我来说显然不同,但一旦它们被折叠、纺锤、残缺和转换,它们就根本没有什么不同。

那么,这里的要点是什么?

1 - 对于 OP 的原始问题 - 除了使用 NUMBER 之外,您还必须想出另一种方法来比较您的数字字符串,因为 Oracle 的 NUMBER 类型不能容纳 256 个数字值。我建议您通过确保所有值的长度均为 256 位来规范化字符串,根据需要在左侧添加零,然后字符串比较应该可以正常工作。

2 - 浮点数通过否定证明(你最喜欢的神/神)的存在,因为它们显然是(你最喜欢的邪恶拟人化)的作品。每当你与他们一起工作时(我们迟早都必须这样做),你应该记住,他们是恶毒的恶毒副产品,等着在你最意想不到的时候攻击你。

3 - 没有第三点!(对于那些无需借助颅外搜索引擎就可以识别的人,还有额外的功劳:-)

分享和享受。

于 2012-05-30T11:58:18.430 回答
4

如果您的意思是列中的数字可能很大(256 位),您可以尝试这样的操作:

SELECT numbers
FROM (
  SELECT numbers
  FROM table_name
  ORDER BY LPAD(numbers, 256) DESC
)
WHERE rownum = 1

或像这样:

SELECT LTRIM(MAX(LPAD(numbers, 256))) AS numbers
FROM table_name
于 2012-05-30T10:01:01.603 回答