When I insert a DOUBLE, why do I see a value like 9.755046187483832e17 when I select that value? How can I retrieve a number like 975504618748383289 instead?
You're probably looking for the FORMAT or ROUND function:
Using FORMAT(), depending on your locale and your specific needs, you might have to replace the thousands-separator:
mysql> SELECT FORMAT(9.755046187483832e17,0);
975,504,618,748,383,200
mysql> SELECT REPLACE(FORMAT(9.755046187483832e17,0), ',','');
975504618748383200
On the other hand, ROUND() being a numeric function, it only outputs digits:
mysql> SELECT ROUND(9.755046187483832e17,0);
975504618748383200
See http://sqlfiddle.com/#!2/d41d8/17614 for playing with that.
EDIT: As you noticed, the last two digits are rounded to 00. That's because of DOUBLE precision limits. You have to remember that double are approximate. If you need precise values and/or more digits than available with the 16-bits precision of double, you probably needs to change your column's type to DECIMAL. By default DECIMAL has 10 digits precision (10 base 10 digits). You could explicitly request up to 65 digits.
For example, if you need up to 20 digits precision, you write something like that:
CREATE TABLE tbl (myValue DECIMAL(20), ...
See http://dev.mysql.com/doc/refman/5.6/en/fixed-point-types.html
Please note however than things are not that simple. Selecting the decimal column might silently convert it to double (or bigint ?) thus loosing the extra precision. You might have to explicitly cast to string in order to preserve the full precision. That means the you might have to deal with that at application level.
create table tbl (dblValue DOUBLE, decValue DECIMAL(20,0));
insert into tbl values (975504618748383289, 975504618748383289);
SELECT dblValue, decValue FROM tbl;
--> DBLVALUE DECVALUE
--> 975504618748383200 975504618748383200
SELECT CAST(dblValue AS CHAR), CAST(decValue AS CHAR) FROM tbl;
--> CAST(DBLVALUE AS CHAR) CAST(DECVALUE AS CHAR)
--> 9.755046187483832e17 975504618748383289
See http://sqlfiddle.com/#!2/d5f58/2 for examples.
The double has a precision of about 16 digits. If you need more precision you have two options.
If the value is an integer, you can use bigint up to about 19 digits of precision.
Better is decimal which supports up to 65 digits. For instance, the following returns an error:
select format(v*v*v*v*v*v*v*v, 0)
from (select 1001 as v) t
Because the value of v is treated as a bigint.
However, the following works very nicely:
select format(v*v*v*v*v*v*v*v, 0)
from (select cast(1001 as decimal(65, 0)) as v) t
Returning 1,008,028,056,070,056,028,008,001 -- which is the precise answer.
If you need precision up to 65 places, then use decimal. Beyond that, you may have to write your own routines. If you are not doing arithmetic on the field, then consider storing it as a string.
Related
I am trying to pull data from Maria DB. The datatype in schema is DECIMAL (12, 8).
In my program when I query using following query. it trucates to 4 (or 3) decimal places and also round off.
select CAST(FORMAT(latitude, 100) AS FLOAT) latitude from mytable
it returns 36.173 . In DB it is stored as 36.17298200
I want it to return as 36.172982
To use the number in calculations, simply use it. No conversion, no CAST.
To dislay it to 6 decimal places, do that on SELECTing:
SELECT FORMAT(latitude, 6) ...
FORMAT(..., 100) should give you lots of decimal places.
FLOAT does not have enough precision to distinguish more than 6 or 7 significant decimal places. That is, the first and third numbers nere are the closest representable numbers in FLOAT:
x4210b122 --> 36.172981262207
36.17298200
x4210b123 --> 36.172985076904
Double:
x40421624463065f9 --> 36.1729819999999975
For Latitude and Longitude:
FLOAT has a resolution of 1.7 m or 5.6 ft -- good enough for Vehicles
DECIMAL(8,6) 16 cm 1/2 ft -- Friends in a mall
According to official MySQL documents:
The DECIMAL and NUMERIC types store exact numeric data values. These types are used when it is important to preserve exact precision, for example with monetary data. In MySQL, NUMERIC is implemented as DECIMAL, so the following remarks about DECIMAL apply equally to NUMERIC.
Floating-Point Types (Approximate Value) - FLOAT, DOUBLE
So you should be writing something similar to:
select CAST(FORMAT(latitude, 100) AS DECIMAL(8,6)) latitude from mytable
As 8 is the total number of digits and 6 is precision.
I want do column for percents..
I need write: 1.00, 2.00, 99.99, 100.. %
How I can use double type for this?
Now I have:
Double(4,2)
But when I write 100 in column I get error:
Numeric value out of range: 1264 Out of range value for column
Look at the answer here (doubleand decimal have the same syntax) or the MySQL manual:
DOUBLE[(M,D)]
M is the total number of digits and D is the number of digits following the decimal point. If M and D are omitted, values are stored to the limits permitted by the hardware. A double-precision floating-point number is accurate to approximately 15 decimal places.
In short, DOUBLE(4,2) means at most 4 digits, with 2 digits after the decimal point. So to support two digits decimals until 100, you need:
double(5,2) unsigned
Note that the unsigned is not mandatory, but can be more performant and safe if you know you won't need negative values.
double(4,2) means a double with a total of four digits, two of them right of the decimal point, meaning you only have 4-2=2 digits to the left of it. 100 has three digits to the left of the decimal point, hence the error. Using double(5,2) instead should fix the issue.
From MySQL docs
MySQL permits a nonstandard syntax:
FLOAT(M,D) or REAL(M,D) or DOUBLE PRECISION(M,D).
Here, (M,D) means than values can be stored with up to M digits in total,
of which D digits may be after the decimal point.
For example,
a column defined as FLOAT(7,4) will look like -999.9999 when displayed.
MySQL performs rounding when storing values, so if you insert 999.00009 into a FLOAT(7,4) column, the approximate result is 999.0001
Coming to your problem, you need to increase size of M. i.e. Double(5,2)
I noticed one more thing will help someone.
IN DOUBLE(M,D) M is represent number of total digit including D, and D is represent the numbers after decimal,
If some one assign same value of M and D then you can only set value after decimal point but not before it.
Here i try to explain with an example,
If you want assign data type value like DOUBLE(5,5), so you can only enter a value like 0.00001 to 0.99999 but you can not 1.0001 or 1.0000.
There is also limit of assign D, you can not assign D greater then to M, its only M >= D
I'm trying to truncate a double with 4 decimals, but I get the last digit rounded (and the double has 4 decimals only!)
double:
-2.5805
SELECT TRUNCATE(double, 4) FROM `table`
Result:
-2.5804
What's more interesting is that:
SELECT TRUNCATE(mycol, 4) AS col1, TRUNCATE(-2.5805, 4) AS col2
FROM mytable
returns:
col1 | col2
--------+--------
-2.5804 | -2.5805
Demo here
The double data type is a floating point type, meaning these numbers are not stored as exact numbers. As MySQL documentation on floating point types explains:
Because floating-point values are approximate and not stored as exact
values, attempts to treat them as exact in comparisons may lead to
problems. They are also subject to platform or implementation
dependencies.
This means that the number -2.5805 is not an exact number when it is stored as a double. The truncate() function, however, returns an exact number with an exact number of digits. When the -2.5805 (as double) is expanded, the 4th decimal digit is 4.
The TRUNCATE(-2.5805, 4) expression returns -2.5805 because MySQL treats numeric literals expressed with fixed number of decimal digits as decimal data type, which is an exact data type. Therefore, the truncate() function just simply returns the same number of decimal digits.
I need to store numbers like
21000
1.0002
0.00230235
12323235
0.2349523
This is sensordata so it is important to keep the exact value.
THere are many options.
My solution would be to multiply all values by 1 million, and store them as a bigint. Would that make sense?
That makes sense but I'd recommend that you just use the decimal datatype: https://dev.mysql.com/doc/refman/5.7/en/precision-math-decimal-characteristics.html
If you were to multiply by million and if a dataset you receive has one more decimal than you'd expect, you'd end up multiplying that number by 10 million and all other numbers by 10. Instead, using the decimal datatype will give you 30 numbers to the right of the decimal.
The declaration syntax for a DECIMAL column is DECIMAL(M,D). The
ranges of values for the arguments in MySQL 5.7 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.
and
The SQL standard requires that the precision of NUMERIC(M,D) be
exactly M digits. For DECIMAL(M,D), the standard requires a precision
of at least M digits but permits more. In MySQL, DECIMAL(M,D) and
NUMERIC(M,D) are the same, and both have a precision of exactly M
digits.
For a full explanation of the internal format of DECIMAL values, see
the file strings/decimal.c in a MySQL source distribution. The format
is explained (with an example) in the decimal2bin() function.
To format your numbers, you could do formatting like this answer describes: Format number to 2 decimal places
Example
create table test (
price decimal(40,20)
);
-- all the above insertions will succeed cleanly
insert into test values (1.5), (1.66), (1.777), (1.12345678901234567890);
-- notice we have 21 digits after decimal
-- MySQL will insert data with 20 decimal and add a warning regarding data truncation
insert into test values (1.123456789012345678901);
Data
select * from test
price
1.50000000000000000000
1.66000000000000000000
1.77700000000000000000
1.12345678901234567890
1.12345678901234567890
select cast(price as decimal(40,2)) from test
price
1.50
1.66
1.78
1.12
1.12
Using MySQL 5.0.27
This query:
SELECT CAST('543.21' AS DECIMAL(100,2))
returns 543.21
So does this one:
SELECT CAST('543.21' AS DECIMAL(2,2))
In fact, I am having trouble figuring out what effect the parameter has. I am using it to aggregate numeric values in a varchar column (for legacy reasons!!) and round off to 2 decimal places.
Should I just pick a high number?
It describes how many total digits a field (or variable) will be able to store.
DECIMAL(100,2) - 100 total digits, 98 before, 2 after a decimal separator
DECIMAL(2,2) 2 total digits, 0 before, 2 after a decimal separator
Explained here:
http://dev.mysql.com/doc/refman/5.1/en/numeric-types.html
[added]
For rounding just use ROUND() function.