2012-05-30 52 views
2

如果有人將某列設置爲VARCHAR2(256 CHAR),並且此列中只有數字,該怎麼辦?我想獲得最高的數字。問題是:數字是> 999999,但最大的一個varchar總是給我一個最大數999999在VARCHAR中使用max來獲得結果> 999999?

我試過to_number(max(numbers), '9999999999999'),但我仍然得到999999回來,在那個不能。有任何想法嗎?謝謝

+0

不要試圖解決這樣一個不好的DB模型。您需要修復模型而不是查詢。將數字存儲在varchar列中(幾乎)總是一個非常糟糕的主意。 –

+0

@a_horse_with_no_name:我知道,壞消息是:它不是我的數據庫,也不允許改變它的內容^^ – sabisabi

回答

7

最好的辦法是

首個解決方案 轉換列數字

第二種解決 轉換成你的數字查詢數據比獲取數據...

示例

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

它必須是這樣的,因爲如果你TO_NUMBER()之前調用MAX(),它會按字母順序排序,然後999999是大於100000000000.請注意使用TO_NUMBER()爲VARCHAR2列即被如果列中包含任何非數字字符,則存在INVALID_NUMBER異常的風險。這就是首選解決方案的原因。

+2

+1。因爲如果在TO_NUMBER之前執行MAX,它將按字母順序排序,然後999999大於100000000000. – Thilo

+0

Oracle能否區分'999 ... 999'(256'9's)和'999 ... 998 '(255'9's後跟'8')這樣? –

+0

@AndriyM:'to_number'將考慮所有數字。 –

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 
6

在Oracle,NUMBER類型包含基數爲100的浮點值,其精度爲38位有效數字,最大值爲9999 ...(38 9)x 10^125。有兩個問題 - 第一個問題是NUMBER是否可以包含從256個字符的字符串轉換而來的值,第二個問題是如果可以區分兩個數字「close」的值。

讓我們從一個256個字符的字符串開始,嘗試將它轉換爲數字。最明顯的事情是:

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

執行上面我們得到:

ORA-01426: numeric overflow 

其中,稍早注意,我們的預期。 NUMBER可以處理的最大指數是125 - 在這裏我們試圖將一個值轉換爲256位有效數字。 NUMBER's無法處理此問題。如果我們削減位數下降到125,如下所示:

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

它工作正常,我們的答案吧1E125。

< 眨眼>

哇!等待!!什麼???答案是 x 10^125 ???那9個呢?!?!?!?

還記得前面我已經提到,Oracle數字是浮點值與38的最大精度和125最大的指數從視圖的TO_NUMBER 125 9點的所有串在一起,不能精確表示 - 數字太多(記住,最高精度爲38(稍後更多))。所以它可以做到絕對的最好 - 它將前38個數字(全都是9)轉換成數字,然後說:「我應該如何最好地把它做出來,使結果A)代表輸入,B)與我一樣接近可以得到我所得到的?「。在這種情況下,它看數字39,看到它是9,並決定向上取整。由於所有其他數字也是9,所以它繼續四捨五入,直到它以1作爲剩餘的尾數。

*之後,回到了牧場... *

OK,前面我已經提到這個數字的38位精度。這並非完全是是真的 - 它實際上可以區分高達40位數字的精度值,至少有時候,如果風是正確的,並且你會走下坡路。這裏有一個例子:

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

這兩個各值有40位(計數作爲一個練習的非常厭倦讀者:-)。如果您執行上述操作,則會返回'較大',顯示兩個40位數值的比較成功。

現在玩一些樂趣。如果您爲每個字符串添加一個附加的「9」,並設置一個41位數值,並重新執行該語句,它將返回「不會更大」。

< 眨眼>

WAIT!什麼??哇!那些值是明顯是不同!即使是TotalFool(TM)也可以看到!

這裏的問題是41位數字的數字超過了NUMBER類型的精度,因此當TO_NUMBER發現它有一個這麼長的值時,它開始丟棄右邊的數字。因此,儘管這兩個非常大的數字分別是,顯然與你我不一樣,但一旦它們被摺疊,紡織,殘缺和轉換,它們就完全沒有區別。

那麼,這裏有什麼呢?

1 - 業務方案的原來的問題 - 你必須想出另一種方式來比較,除了使用NUMBER你的電話號碼串,因爲Oracle的NUMBER類型不能容納256位值。我建議你通過確保所有值都是256位數字,根據需要在左側添加零來規範字符串,然後字符串比較應該可以正常工作。

2 - 浮點數通過否定來證明(你最喜歡的神/神在這裏)的存在,因爲它們顯然是(你最喜歡的邪惡化身在這裏)的工作。每當你和他們一起工作時(我們都必須,遲早),你應該記住,他們是惡性惡魔的惡毒副產品,等待你在最不經意的時候抨擊你。

3 - 有沒有點三!(額外的功勞,可以識別而不訴諸於頭顱搜索引擎這些來自:-)

分享和享受。

+0

+1非常豐富(和有趣)。 –

相關問題