簡體   English   中英

在varchar列中查找非數值

[英]Finding non-numeric values in varchar column

要求:

通用查詢/函數,用於檢查表的varchar列中提供的值是否實際上是數字,並且精度不超過允許的精度。

可用值:

表名稱,列名稱,允許的精度,允許的比例

一般建議是創建一個函數並使用to_number()來驗證值,但不會驗證允許的長度(精度標度)。

我的解決方案:

使用Regexp驗證號碼NOT REGEXP_LIKE(COLUMN_NAME, '^-?[0-9.]+$')

驗證左部分的長度(小數點前)(我不知道它的實際名稱是什么),因為對於小數位數,oracle會根據需要自動舍入。 由於實際列為varchar,因此我將使用substr,instr在小數點左側找到該組件。

如上所述,Regexp允許使用123 ... 123124..55之類的數字,我還將驗證小數點的數量。 [如果> 1,則報錯]

查詢以查找無效號碼:

Select * From Table_Name 
Where
(NOT REGEXP_LIKE(COLUMN_NAME, '^-?[0-9.]+$')
OR
Function_To_Fetch_Left_Component(COLUMN_NAME) > (Precision-Scale)
/* Can use regexp_substr now but i already had a function for that */
OR
LENGTH(Column_Name) - LENGTH(REPLACE(Column_Name,'.','')) > 1
/* Can use regexp_count aswell*/)

我對自己的解決方案感到滿意並感到滿意,直到一列只有“。”為止。 價值逃脫了我的支票,我看到了支票的局限性。 盡管添加另一個檢查來驗證這一點也可以解決我的問題,但是整個solution對我而言似乎效率很低。

我將非常感謝更好的解決方案(以任何方式)。

提前致謝。

尋找:

  • 一個或多個數字(可選),后跟小數點和零個或多個數字; 要么
  • 前導小數點(無前導單位數字),然后是一個或多個(十進制)數字。

像這樣:

Select *
From   Table_Name 
Where  NOT REGEXP_LIKE(COLUMN_NAME, '^[+-]?(\d+(\.\d*)?|\.\d+)$')

如果您不想在數字字符串中使用零填充值,則:

Select *
From   Table_Name 
Where  NOT REGEXP_LIKE(COLUMN_NAME, '^[+-]?(([1-9]\d*|0)(\.\d*)?|\.\d+)$')

具有精度和小數位數(假設它按照NUMBER( precision, scale )數據類型和scale < precision起作用):

Select *
From   Table_Name 
Where  NOT REGEXP_LIKE(COLUMN_NAME, '^[+-]?(\d{1,'||(precision-scale)||'}(\.\d{0,'||scale||'})?|\.\d{1,'||scale||'})$')

或者,對於具有精度和小數位數的非零填充數字:

Select *
From   Table_Name 
Where  NOT REGEXP_LIKE(COLUMN_NAME, '^[+-]?(([1-9]\d{0,'||(precision-scale-1)||'}|0)(\.\d{0,'||scale||'})?|\.\d{1,'||scale||'})$')

或者,對於任何精度和規模:

Select *
From   Table_Name 
Where  NOT REGEXP_LIKE(
             COLUMN_NAME,
             CASE
               WHEN scale <= 0
               THEN '^[+-]?(\d{1,'||precision||'}0{'||(-scale)||'})$'
               WHEN scale < precision
               THEN '^[+-]?(\d{1,'||(precision-scale)||'}(\.\d{0,'||scale||'})?|\.\d{1,'||scale||'})$'
               WHEN scale >= precision
               THEN '^[+-]?(0(\.0{0,'||scale||'})?|0?\.0{'||(scale-precision)||'}\d{1,'||precision||'})$'
             END
           )

精度意味着您最多需要數字中的allowed_precision數字(嚴格來說,不計算前導零,但我會忽略它)。 該小數位數表示最多allowed_scale可以在小數點后。

這建議一個正則表達式,例如:

[-]?[0-9]{1,<before>}[.]?[0-9]{0,<after>}

您可以構造正則表達式:

NOT REGEXP_LIKE(COLUMN_NAME,
                REPLACE(REPLACE('[-]?[0-9]{1,<before>}[.]?[0-9]{0,<after>}', '<before>', allowed_precision - allowed_scale
                               ), '<after>', allowed_scale)

現在,可變正則表達式的效率非常低。 您也可以使用like和其他功能來執行邏輯。 我認為條件是:

(column_name not like '%.%.%' and
 column_name not like '_%-%' and
 translate(column_name, '0123456789-.x', 'x') is null and
 length(translate(column_name, '-.x', 'x') <= allowed_precision and
 length(translate(column_name, '-.x', 'x') >= 1 and
 instr(translate(column_name, '-.x', 'x'), '.') <= allowed_precision - allowed_scale
)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM