要求:
通用查询/函数,用于检查表中varchar列中提供的值是否实际为数字&精度不超过允许的精度。
可用值
Table_Name,Column_Name,Allowed Precision,Allowed Scale
一般建议是创建一个功能&使用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
整体看起来效率非常低。
我会非常感谢[以任何方式]提供更好的解决方案。
提前致谢。
答案 0 :(得分:2)
寻找:
像这样:
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
)
答案 1 :(得分:0)
精度意味着您希望数字中最多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
)