我有一个VARCHAR
字段,其中存储着0.00000000
之类的值。
我想对所有这些SUM
字段VARCHAR
进行报表查询,这意味着我必须将它们转换为数字以添加它们。
这是我的查询,该查询可以正常工作,但不会产生任何错误,但是会返回错误的数字:
SELECT SUM(CAST(IFNULL(tx.received_amount, '0.00000000') AS DECIMAL(16, 16)))
FROM account
JOIN account_invoice
ON account_invoice.account_id = account.id
JOIN withdrawal
ON withdrawal.invoice_id = account_invoice.invoice_id
JOIN tx
ON tx.id = withdrawal.tx_id
AND tx.currency = 'BTC'
AND tx.created_at > DATE_SUB(NOW(), INTERVAL 7 DAY)
WHERE account.id = 1
这就是我得到的: 100 x 1.12345678 = 100.00000000
这就是我应该得到的: 100 x 1.12345678 = 112.34567800
为什么SUM
不将小数点后的数字相加?
答案 0 :(得分:2)
您没有根据使用情况使用DECIMAL
数据类型。 DECIMAL(16, 16)
声明一个十进制数字,其总数为16个数字,则为16个十进制数字。该值不能大于1
。
考虑:
SELECT CAST('1.12345678' AS DECIMAL(16, 16))
返回:0.9999999999999999
。
您可能希望使用类似DECIMAL(16, 8)
之类的东西,因为您的字符串似乎有8位小数。
DECIMAL
列的声明语法为DECIMAL(M,D)
。自变量的值范围如下:
M
是最大位数(精度)。它的范围是1
至65
。
D
是小数点(小数点)右边的位数。它的范围是0
至30
,并且不得大于M
。
答案 1 :(得分:1)
GMB的答案通常是最好的选择,但是如果您确实需要输出(a_really_precise_number)* 100,则可以在应用程序端通过将其作为字符串实际传递到支持任意大数的语言中进行处理,然后进行强制转换应用程序端。如果您的数据库中的数字比16位数字更精确,则您可能已经在应用程序中使用了支持此数字的数字。
在某些情况下,您正在查看来自其他来源的数据,并且您所选择的语言所具有的数字比您所选择的语言更为精确。许多不原生支持这些较大数字的语言可能都有可用的库,它们可以进行花式解析来对作为字符串的字符串进行数学运算,但是如果您需要处理非常大的数字或数据集,它们的运行速度可能会有些慢。
第三个选项,如果只是将其乘以10的幂(例如N * 100)并输出结果,则将其作为字符串传递给应用程序,然后只需解析它即可将小数点移到2位:
function shiftDec(str, shift){
// split on decimal point
var decPoint = str.indexOf(".");
var decInt = str.substr(0, decPoint);
var decMod = str.substr((decPoint+1));
// move decimal 'shift' places to simulate N*100.
if(shift > 0){
var shiftCopy = decInt .substr(0,shift);
decInt = decInt + shiftCopy;
decMod = decMod .substr(shift);
} else {
var shiftCopy = decInt .substr((decInt.length + shift));
decInt = decInt .substr(0,(decInt.length + shift));
decMod = shiftCopy + decMod;
}
return decInt + '.' + decMod;
}
var result = shiftDec("1234567891234567.8912345678912345", 2);
document.write(result);
答案 2 :(得分:0)
您不应使用DECIMAL(16,16)
Boost.Python.ArgumentError: Python argument types in
X.getItem(ChildClassOfX)
did not match C++ signature:
getItem(X_wrap {lvalue}, Z* a=0)
getItem(X_wrap {lvalue}, Z* a=0)
99.999 ...
SELECT 100 * CAST('1.123' AS DECIMAL(16,16))
112.300 ...