验证数字精度/比例

Posted

技术标签:

【中文标题】验证数字精度/比例【英文标题】:Validating number precision/scale 【发布时间】:2011-09-10 01:41:02 【问题描述】:

如何验证从表单发布的数字的精度/比例,以确保它可以存储在 Oracle NUMBER 列中?例如:

<input type="number" name="foo" value="123.45" />

用户将表​​单提交到 php 后端...

<?php
function isValidNumber($number, $precision, $scale) 
    // ???

    return $isValid;


// The precision and scale here are actually dynamic
$isValid = isValidNumber($_POST['foo'], 5, 2);

...我希望能够验证数字而不尝试在 Oracle 中插入/更新它并处理任何精度溢出错误(主动设计,而不是被动设计)。我还没有想出一种准确验证所有各种边缘情况的方法(Oracle 不会产生比例溢出错误 - 它只是四舍五入到最大值,但这种四舍五入可能导致精度溢出,这确实会产生错误等)。

【问题讨论】:

您使用什么库来连接您的 Oracle 数据库? 【参考方案1】:
function isValidNumber($number, $precision, $scale) 
    $isValid = false;
    if (is_numeric($number)) 
        $num = round(abs($number), $scale);
        $max = str_repeat('9',$precision - $scale).'.'.str_repeat('9',$scale);
        $isValid = $num <= $max;
    
    return $isValid;

isValidNumber($number, 5, 2) 的输出

123.456   (valid)
9999.999  (invalid)
99999.999 (invalid)
12.003    (valid)
999.99    (valid)
999.999   (invalid)
1234.5    (invalid)

最后

isValid(1234567890123456789012345678.90, 30, 2) == **valid**

【讨论】:

感谢您的回答,但是对于有效的 Oracle 输入,此功能失败。例如,“123.456”是 NUMBER(5, 2) 列的有效输入。 Oracle 将简单地将其四舍五入并将其存储为“123.46”。 你不是说要阻止 Oracle 舍入它吗? 不,我只是想确保我给 Oracle 的任何数字都不会产生溢出错误。这个函数可以做到这一点,但它也会阻止 Oracle 不会产生错误的值。 好的,我更改了上面代码中的第 4 行。看看是否有帮助。 :) 这更好,但在比例舍入产生精度错误的情况下仍然失败。例如,isValidNumber("999.999", 5, 2) 应该返回 false,但您的版本返回 true。它应该返回 false,因为 Oracle 将 999.999 舍入到 1000.00,因为比例为 2。1000.00 的精度为 6,因此会产生溢出错误。【参考方案2】:

您可以使用 n 种方法来实现这一点。以下可以作为起点

使用 html5 验证的客户端验证

建议的方法是仅使用 HTML5 使用基于正则表达式模式的匹配。

input type="text" pattern="regex"

免责声明:模式逻辑尚未经过测试,因此您必须在任何地方使用之前对其进行测试

-?([0-9]0,precision-scale\.[0-9]1,scale|[0-9]1,precision-scale)

相同的正则表达式逻辑也可以用于以下任何有自己的加号和减号的层

使用 Java 脚本验证的客户端 使用 php 验证的服务器端 在 DB 层进行验证并在不同的地方抛出错误 层

【讨论】:

感谢您的回答,但它没有解决比例舍入问题。 对不起,无法得到这个...如果数字不在配置的比例值中,并且您想在 UI 层中处理这个问题,Oracle 会四舍五入。 Regex 模式将匹配,您可以对不匹配的模式发出验证警告。我在这里错过了什么吗? 您给出的正则表达式匹配“999999999999.999999999999”和其他可能导致数据库错误的无效数据。 谢谢,但新的正则表达式仍然匹配“999999999999.999999999999”等无效数据。 客户端验证不可靠。始终在服务器端进行验证。【参考方案3】:

获取字符串的长度,获取小数的位置 这将为您提供总小数位数

$len = strlen($num); 
$p = strpos($num, '.'); 
$dec_plcs = ($len - $p) - 1;

【讨论】:

感谢您的反馈,但这并不能验证精度或规模。超过 位小数的数字仍然有效。 我误会了。我认为您需要验证一定数量的小数位。你能再给我解释一下吗,我帮你找答案。 我正在寻找一个用 PHP 编写的函数,它会告诉我 Oracle 是否允许我根据其精度和规模将给定数字存储在列中。 如果您担心 Oracle 会更改该值,也许解决方案是将其存储为字符串。您是否需要在数据库级别将其作为数字进行处理,还是有可能? 我只是想确保我的表单输入在插入/更新中使用时不会产生 Oracle 精度溢出错误。例如,如果 $_POST['foo'] 是“9999999999999.99999”,我尝试将其插入到 NUMBER(5,2) 列中,Oracle 将产生精度溢出错误。

以上是关于验证数字精度/比例的主要内容,如果未能解决你的问题,请参考以下文章

如何解释数据库中数字的精度和比例?

使用 c# 设置自动计算数字的比例和精度

检测 Oracle 数字数据类型的实际精度和比例

具有任意精度和一定比例的数字格式的 Oracle to_char 函数

NSDecimalNumber 值的比例和精度

MySQL数据类型之数字相关