在Mysql或PHP中处理十进制精度
在Mysql或PHP中处理十进制精度,php,mysql,decimal,Php,Mysql,Decimal,我有一个MySQL表,即estimate\u item,它包含几个列,这些列包含固定精度的十进制值。这是我的桌子结构 表名:估算项目 在使用PHP检索记录时,我使用MySQL函数进行一些基本计算,我使用的SQL查询如下 SELECT COUNT(ei.item_id) as total_item, SUM(ei.quantity) as total_quantity, SUM(ei.number_of_carton) as total_carton, SUM(
我有一个MySQL表,即
estimate\u item
,它包含几个列,这些列包含固定精度的十进制值。这是我的桌子结构
表名:估算项目
在使用PHP检索记录时,我使用MySQL函数进行一些基本计算,我使用的SQL查询如下
SELECT
COUNT(ei.item_id) as total_item,
SUM(ei.quantity) as total_quantity,
SUM(ei.number_of_carton) as total_carton,
SUM(ei.number_of_carton * ei.cbm_per_carton) as total_cbm,
SUM(ei.quantity * ei.cost) as total_cost,
SUM(ei.quantity * ei.rate) as total_rate,
e.commission_amount,
SUM(ei.quantity * ei.rate) + e.commission_amount as total_amount
FROM
ai_estimate e
LEFT JOIN
ai_estimate_item ei ON ei.estimate_id = e.id
WHERE
ei.estimate_id = ?
例如,上面的查询返回结果
+------------+----------------+--------------+-----------+------------+------------+-------------------+--------------+
| total_item | total_quantity | total_carton | total_cbm | total_cost | total_rate | commission_amount | total_amount |
+------------+----------------+--------------+-----------+------------+------------+-------------------+--------------+
| 2 | 120 | 807 | 1122.6440 | 2.7500 | 137.5000 | 1500.00 | 1637.5000 |
+------------+----------------+--------------+-----------+------------+------------+-------------------+--------------+
由于以下列包含4个精度值total\u cbm\u total、total\u cost、total\u rate、total\u amount
,因此我想以这种方式对所有四列的值进行取整
a) 如果值为1122.6440
,则将其四舍五入为1122.644
b) 如果值为2.7500
,则将其四舍五入到2.75
c) 如果值为137.5000
,则将其四舍五入到137.50
d) 如果值为1200.0000
,则将其四舍五入到1200.00
i、 e我希望这些值至少包含两个精度,根据值的不同,精度可以达到3或4
我有没有办法直接在MySQL中实现这一点?还是PHP方式
感谢并问候。如果您在MySQL中这样做,我的猜测是您需要在添加一个案例时使查询变得过于复杂。。。结束 所以我会用PHP来实现
function reprecise($value)
{
$two_digit = number_format($value, 2);
$three_digit = number_format($value, 3);
return (float)$two_digit == (float)$three_digit ? $two_digit : $three_digit;
}
这采用了一种技巧——首先计算两位和三位数字的表示,然后检查它们是否是相同的浮点数。如果是,则三位版本的最后一位必须为零,并使用两位版本
要扩展到2、3或4位数,您可以在一个周期内完成:
function reprecise($value)
{
$digits = 4;
for ($rep = number_format($value, $digits--); $digits >= 2; $digits--)
{
$new = number_format($value, $digits);
if ($new != $rep)
break;
$rep = $new;
}
return $rep;
}
或者,由于字符串函数很可能比数字格式快:
function reprecise($value)
{
$digits = 9;
$base = strrev(number_format($value, $digits));
for ($i = 0; $i < $digits-2; $i++)
if ($base[$i] != '0')
break;
return strrev(substr($base, $i));
}
函数重复精度($value)
{
$digits=9;
$base=strev(数字格式($value,$digits));
对于($i=0;$i<$digits-2;$i++)
如果($base[$i]!='0')
打破
返回strev(substr($base,$i));
}
一种方法是使用正则表达式删除小数点后数字末尾的所有0
,然后用两位小数格式化一个数字,并比较两个结果-返回最长的结果(按字符串)。虽然这可以在mysql中完成,但在php中要容易得多:
//$input - number to format
//$num - minimum number of decimal places to keep
function reformat($input, $num) {
$parse = preg_replace('/(\.[1-9]*)0+$/', "$1", $input);
$withmin = number_format($parse, 2);
return strlen($withmin) < strlen($parse) ? $parse : $withmin;
}
/$input-要格式化的数字
//$num-保留的最小小数位数
函数重新格式化($input,$num){
$parse=preg\u replace('/(\.[1-9]*)0+$/',“$1”,$input);
$withmin=number\u格式($parse,2);
返回strlen($withmin)
在数据库端,注意cost、rate和cmb\u per\u carton列的尾随0的数量是由表结构预定义的,在您的示例中是40:
cost DECIMAL 19,4
rate DECIMAL 19,4
cmb_per_carton DECIMAL 19,4
如果对这些字段进行操作,结果自然会有相同的尾随0
PHP方面,我刚刚破解了一个简单的函数,它将完成您想要的功能:
function getDecimalFormatted($value, $minPrecision) {
$value = (float) $value;
return ((round((($value - floor($value))*pow(10, 5)))%1000) > 0) ? $value : number_format($value, $minPrecision, '.', '');
}
用法示例:
$value = "1234.71200";
echo getDecimalFormatted($value, 2)."\n<br>";
$value = "1234.70000";
echo getDecimalFormatted($value, 2)."\n<br>";
根据您给出的示例,您所要做的就是截断尾随的零。如果您想在PHP中输出它们,可以使用字符串操作或数字格式函数。如果此时我有值
1200.0000
,则截断尾随的零可能会有问题。我希望有两个尾随的零,以便值应该是1200.00
,不是吗?这是一个很好的方法。当然,随着最大小数位数的增加,它会变得越来越复杂。实际上,OP是处理小数点后2、3或4位的。如果你推断到,比如说小数点后2到10位之间的任何地方,这将变得有点可怕。现在编辑答案。一种更有效的方法是生成最大长度的字符串,然后strev()将其删除,并开始删除最多($digits-2)个连续零,然后再次strev()将其删除。哦,我想我的速度不够快。检查我的版本,我认为我的(几乎)一行是整洁的:)
1234.712
1234.70