I have looked at many questions regarding this problem, but I have not found a solution. Hopefully this is not a duplicate question.
Problem
If I do any of:
INSERT INTO `Numbers`(`Number`) VALUES ('NaN')
INSERT INTO `Numbers`(`Number`) VALUES ('Inf')
INSERT INTO `Numbers`(`Number`) VALUES ('+Inf')
I get 0.0 inserted in the table. Sometimes I get:
Error Code: 1265. Data truncated for column 'Number'
I have also tried different casing and spelling, all with the same effect.
I have even tried:
INSERT INTO `Numbers`(`Number`) VALUES ('1111111111111000000000000000000000000000000000000000000000000000')
How do I insert a NaN floating point number into a MySql table?
If it really isn't possible then what is the reasoning? (Maybe I am using the incorrect version of MySql?)
Using NULL as NaN
The tables where I am actually using this I don't want to allow NULL values in those columns. So I don't like the idea of replacing NaN with NULL somewhere in the ORM layer
To get an overall idea of how MySQL manipulates numbers you can read the following chapters:
Numeric Type Overview and Numeric Types, including Out-of-Range and Overflow Handling
Number Literals
Type Conversion in Expression Evaluation
The last article mentions this:
The server includes dtoa, a conversion library that provides the
basis for improved conversion between string or DECIMAL values and
approximate-value (FLOAT/DOUBLE) numbers
[...]
The dtoa library provides conversions with the following properties. D
represents a value with a DECIMAL or string representation, and F
represents a floating-point number in native binary (IEEE) format.
[...]
conversions are lossless unless F is -inf, +inf, or NaN. The latter
values are not supported because the SQL standard defines them as
invalid values for FLOAT or DOUBLE.
In short:
The SQL standard explicitly bans those values
MySQL complies with the standard in that aspect
Related
Issue
I'm using SQLite and I've got a bunch of fields representing measures in millimeters that I'd like to limit to 1 number after decimal point (e.g. 1.2 ; 12.2 ; 122.2 and so on).
I've seen such things as putting DECIMAL(n,1) as the type for example and I tried it but it doesn't seem to constraint the value (I suppose it's because it's not an actual SQLite type).
Do I need to migrate to MySQL for it to work?
EDIT (solution found)
I used Dan04's answer : it's simple and it works really fine :
► Table is as follow :
CREATE TABLE demo(
a REAL CHECK(a = ROUND(a,1)),
b REAL CHECK(b = ROUND(b,1)),
c REAL GENERATED ALWAYS AS (a+b)
)
► Insert corerct data : INSERT INTO demo (a,b) values (41.4,22.6)
► Insert bad data : INSERT INTO demo (a,b) values (1.45,22.68) outputs :
Execution finished with errors.
Result: CHECK constraint failed: a = ROUND(a,1)
At line 1:
insert into demo (a,b) values (1.45,22.68)
You can make a CHECK constraint using the ROUND function. Declare the column as:
mm REAL CHECK(mm = ROUND(mm, 1))
But note that the underlying representation is still a binary floating-point number, with the usual caveats about accuracy.
MySQL's DECIMAL(nn,1) will round to 1 decimal place for storing. That's not the same as a constraint.
When displaying data, your app should round the result to a meaningful precision. (One decimal place is arguably over-kill for weather readings.)
In general, measurements (not money) should be stored in FLOAT. This datatype (in MySQL and many other products) provides 7 "significant digits" and a reasonably high range of values.
FLOAT has sufficient precision when used for latitude and longitude to distinguish two vehicles, but not enough precision to distinguish two people embracing.
(Sorry, I can't speak for SQLite. If FLOAT is available then I recommend you use it and round on output.)
When I insert a number as 1234567.1234567 it will translate it to 1234567.1250.
How do I make it to save the correct number?
When I insert a number as 1234567.1234567 it will translate it to 1234567.1250
FLOATs are saved in four bytes, allowing for about 232 different values.
1234567.1234567 is not one of them. Encodable values are all some limited integer times a power of 2.
The closest encodable value is 1234567.125 or 9876537*2-3.
Code could use DOUBLE yet a similar issue applies.
The closest is about 1234567.1234567000065..., may be close enough for OP's purpose.
Database field name with datatype value float(5,2)
Inserted value
7.80
78.00
My query in modal
$checkValue = static::find()->where(['value' => $this->value])->one();
If i passed $this->valueequal to 78.00 or 78.000 then it returns proper result.
But if I pass 7.80 or 7.8 then 0 rows are returned. Why?
i suspect internally mysql treats 7.8 as something like 7.800000000001 so you cannot get a result if you compare with a fixed value.
you may have come across mysql's reference manuals on datatypes.
please note the following:
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.
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. For more information, see Section B.5.4.8, “Problems with Floating-Point Values”
For maximum portability, code requiring storage of approximate numeric data values should use FLOAT or DOUBLE PRECISION with no specification of precision or number of digits.
for most applications you can safely use a fixed point type.
essentially using decimal(5,2) instead of float(5,2) ensuring that any value displayed is the exact value stored internally.
when applicable rounding happens on insert with the "round half up" rule to the precision you specifed and is somewhat more intuitive and easy to manage
I resolve this issue with double datatype
value double(5,2)
This question already has answers here:
Difference between float and decimal data type
(12 answers)
Closed 9 years ago.
I have a table contain column float(10,5) and decimal(10,5)
I update the table to be:
update table1
set decimaltesting = 12311123123123123.456789,
floattesting = 12311123123123123.456789;
The result become:
decimal = 99999.99999
float = 100000.00000
but if I change column to float(6,3) and decimal(6,3) and update it with the same value as above
The result become:
float = 999.999
decimal = 999.999
Why for the first scenario, float value will be 100000.00000?
Garbage in - garbage out
Remember this simple rule. Your statement will not be correct in common case - since, for example, with strict sql mode it will fail with error. But since you're getting results as you've described, I assume you have allowed such behavior. The correct point is - that your application is aware about it's models data types - and so such things are under control - and you're not passing garbage to your DBMS, resulting with garbage as well.
Always about precision
Your sample is a good demonstration about - what's the difference between fixed-point and floating-point data types. First thing - according to manual page:
When a floating-point or fixed-point column is assigned a value that
exceeds the range implied by the specified (or default) precision and
scale, MySQL stores the value representing the corresponding endpoint
of that range.
-that is why you're seeing that 999.999 and so on. But - what about strange 100000.00000? The hint is - that you can see this only with floating point field. Why? Because MySQL will convert your out-of-range value to maximum allowed by your field, but, since floating point values are stored approximately, there's no guarantee that final value will hold precision - and, therefore, it may result in your 100000.00000 value. Note, that such thing will never happen with fixed-point data type.
I have the following sql query in mysql:
SELECT *
FROM _t_test
WHERE pret NOT
IN ( 2.6700, 2.6560, 1.8200 )
I would expect the rows with the value 1.8200 not to be shown, yet I still get them.
Am I missing something?
The field "pret" is double(16,4).
This is a rounding error. A double is not an exact value, so 1.8200 isn't represented exactly, so the values are not exactly the same.
For MYSQL floating points, see http://dev.mysql.com/doc/refman/5.0/en/problems-with-float.html
The correct way to do floating-point number comparison is to first
decide on an acceptable tolerance for differences between the numbers
and then do the comparison against the tolerance value. For example,
if we agree that floating-point numbers should be regarded the same if
they are same within a precision of one in ten thousand (0.0001), the
comparison should be written to find differences larger than the
tolerance value
See http://en.wikipedia.org/wiki/Double_precision_floating-point_format