losing decimal precision in string filed when updating MySQL table - mysql

I have a filed with varchar(255) data type. when I run this query :
update sample_tbl
set in_order_real = in_order_real + 21.215541764099030466
where id = 15
it removes extra decimals.
for example in_order_real number is 0 and when I run this query it keeps only some decimals and round up while it is a string field. how can i fix this issue?

You must cast your string value to DECIMAL with proper precision.
CREATE TABLE sample_tbl (id INT, in_order_real VARCHAR(255))
SELECT 15 id, 1.23 in_order_real
UNION ALL
SELECT 16, 1.23;
SELECT * FROM sample_tbl;
id
in_order_real
15
1.23
16
1.23
update sample_tbl
set in_order_real = in_order_real + 21.215541764099030466
where id = 15;
update sample_tbl
set in_order_real = CAST(in_order_real AS DECIMAL(30, 18)) + 21.215541764099030466
where id = 16;
SELECT * FROM sample_tbl;
id
in_order_real
15
22.44554176409903
16
22.445541764099030466
db<>fiddle here
If you don't know actual decimal digits amount then use maximal possible value. Additionally you may trim trailing zeros in the result.

FLOAT holds 24 significant bits -- about 7 decimal digits of significance.
DOUBLE: 53 and 16
So, putting 21.215541764099030466 into a FLOAT will garble the digits after about 7 digits: ~21.21554. For DOUBLE: ~21.21554176409903
Can't do arithmetic in VARCHARs; it is converted either to DOUBLE or DECIMAL.
Where do your numbers come from? For money, use DECIMAL(..., 2); for sensor readings, use FLOAT.

Related

count of rows which are not divided by a number

I have a column like below.
Value
_____
48
48
39
96
50
I want to divide this with 48.
From the above 5 values, row 1,2,4 can be divided, but 3,5 not. I have to do this with SQL.
EG:
select count(*) from tbl where value/42
Result: 2
You are asking for the remainder when an integer is divided by 48. That has a specific name in mathematics, the modulo operation. This is actually a very interesting (to some people) part of number theory and group theory.
Most databases support the modulo operator or function via %. So the idea is:
select value
from t
where value % 48 = 0;
This might be:
where value mod 48 = 0
where mod(value, 48) = 0
depending on the database.
Another method is:
where floor(val / 48) * 48 = val
You can do that with a simple where clause
SELECT value FROM table WHERE value%48 = 0
The modulus operator returns the remainder for the division of the operands which in fact means we are checking if the numbers are divisible (remainder is zero when numbers are divisible)
So, if you are trying to count what’s not divisible then simple use below query
SELECT count(value) FROM table WHERE value%48 != 0
You can use modulus(%) to find the result. Check below query it will help you.
declare #tbl table (val int)
insert #tbl values(48),(48),(39),(96),(50)
select * from #tbl where val % 48 =0
Output
val
48
48
96

SUM on VARCHAR field converted to DECIMAL not adding numbers after decimal

I have a VARCHAR field that stores a value like 0.00000000.
I want to run a report query to SUM all those VARCHAR fields, which means I have to convert them to a number to add them.
Here's my query, which works as far as giving no errors, but it gives the wrong number back:
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
This is what I get: 100 x 1.12345678 = 100.00000000
This is what I should get: 100 x 1.12345678 = 112.34567800
Why is the SUM not adding the numbers after the decimal?
You are not using the DECIMAL datatype accordingly to your use case. DECIMAL(16, 16) declares a decimal number with a total of 16 digits and with 16 decimal digits. This cannot hold a value greater than 1.
Consider:
SELECT CAST('1.12345678' AS DECIMAL(16, 16))
Returns: 0.9999999999999999.
You probably want something like DECIMAL(16, 8) instead, since your strings seem to have 8 decimals.
From the MySQL documentation:
The declaration syntax for a DECIMAL column is DECIMAL(M,D). The ranges of values for the arguments are as follows:
M is the maximum number of digits (the precision). It has a range of 1 to 65.
D is the number of digits to the right of the decimal point (the scale). It has a range of 0 to 30 and must be no larger than M.
GMB's answer is usually the best choice, but if you truly need to output a (a_really_precise_number)*100 you can do it application-side by actually passing it as a string into a language that supports arbitrarily large numbers, then cast it application side. If you have numbers more precise than 16 digits in your database, you are likely already using one that supports this in your application.
In some cases, you are looking at data from another source and you have more precise numbers than your language of choice is designed for. Many languages that don't support these larger numbers natively may have libraries available that do fancy parsing to perform math on strings as strings but they tend to be a bit slow if you need to work with really large numbers or data sets.
A third option if you are just multiplying it by a power of 10 such as N*100 and outputting the result is to pass it to the application as a string, then just parse it to move that decimal over 2 places like this:
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);
You should not use DECIMAL(16,16)
SELECT 100 * CAST('1.123' AS DECIMAL(16,16))
99.999...
SELECT 100 * CAST('1.123' AS DECIMAL(16, 10))
112.300...

MySQL strange behavior when comparing comma-separated string with number

I am experiencing some weird behavior with MySQL. Basically I have a table like this:
ID string
1 14
2 10,14,25
Why does this query pull id 2?
SELECT * FROM exampletable where string = 10
Surely it should be looking for an exact match, because this only pulls id 1:
SELECT * FROM exampletable where string = 14
I am aware of FIND_IN_SET, I just find it odd that the first query even pulls anything. Its behaving like this query:
SELECT * FROM exampletable where string LIKE '10%'
When you compare a numeric and a string value, MySQL will attempt to convert the string to number and match. Number like strings are also parsed. This we have:
SELECT '10,14,25' = 1 -- 0
SELECT '10,14,25' = 10 -- 1
SELECT 'FOOBAR' = 1 -- 0
SELECT 'FOOBAR' = 0 -- 1
SELECT '123.456' = 123 -- 0
SELECT '123.456FOOBAR' = 123.456 -- 1
The behavior is documented here (in your example it is the last rule):
...
If one of the arguments is a decimal value, comparison depends on the
other argument. The arguments are compared as decimal values if the
other argument is a decimal or integer value, or as floating-point
values if the other argument is a floating-point value.
In all other cases, the arguments are compared as floating-point
(real) numbers.

Remove trailing zeros only from int numbers

I have decimal column in db and trying to remove trailing zeros only from int numbers (100, 200, 300) with query in php. I tried with trim/cast functions but 10.50 turned 10.5.
SELECT TRIM(TRAILING '0' FROM `my_column`) FROM `mytable`
200.00
10.50
247.09
would display as
200
10.50
247.09
Use a case expression to determine if a number is an integer using ceil() and if it is format with zero decimals, if not with 2 decimals.
SELECT
CASE WHEN ceil(n) = n THEN format(n, 0) ELSE format(n, 2) END
FROM (
SELECT
1234.5 AS n
UNION ALL
SELECT
1234
) d

Cast as decimal in mysql

I have below table structure and data :
create table sample
(
id INT(10)
);
INSERT INTO sample
values
(23398),
(98743),
(54734);
Now I want to understand CAST function in mysql. Consider following query :
select
cast((id/3) as decimal(2,2)) as cast1,
cast((id/3) as decimal(3,2)) as cast2,
cast((id/3) as decimal(4,2)) as cast3,
cast((id/3) as decimal(5,2)) as cast4,
cast((id/3) as decimal(6,2)) as cast5,
cast((id/3) as decimal(7,2)) as cast6,
id/3 as actualId
from sample;
Please see output of this query at SQL Fiddle.
I am wondering why this query gives 0.99, 9.99 and vice versa.
Can anyone explain it ?
Thanks in advance.
decimal is a type that takes 2 arguments
decimal(size, places) :
size determines how many digits are in the number.
places determines how many of those digits are to the right of the decimal.
decimal(2,2) - .00 - 2 digits both of which are to the right of the decimal
when casting (23398 / 3) = 7799.33333333 to declimal(2, 2) it yields a decimal in the specified amount of space closest to the desired number which is 0.99
decimal(3,2) - 0.00 - 3 digits 2 of which are to the right of the decimal
when casting (23398 / 3) = 7799.33333333 to declimal(3, 2) it yields a decimal in the specified amount of space closest to the desired number which is 9.99
if all of the original numbers were negative you would yield -0.99 and -9.99 because they are the closest numbers to the desired number within the allocated space
As a matter of fact java does something similar if you take the max double and try to convert it to an int you will give the max int which is no where near the max double