I know all the numerical implications, that is, the possible rounding issues inherent to floating point formats, but in my case I have DECIMAL columns in MySQL that I want to convert to DOUBLE straight in the MySQL query rather than down stream.
Could anyone help?
SELECT my_decimal_field + 0E0 FROM my_table
The following quotes from MySQL manual explain how this works:
9.1.2 Numeric Literals
Number literals include exact-value (integer and DECIMAL) literals and approximate-value (floating-point) literals.
Numbers represented in scientific notation with a mantissa and exponent are approximate-value numbers.
12.22.3 Expression Handling
Handling of a numeric expression depends on what kind of values the expression contains:
If any approximate values are present, the expression is approximate and is evaluated using floating-point arithmetic.
Because of the limitations of the built in CAST function in MySQL, it is only possible to convert DECIMAL to DOUBLE with your own user defined cast function.
Sample use case:
SELECT castDecimalAsDouble(0.000000000000000000100000000000);
Result: 1e-23
CREATE DEFINER=`root`#`localhost` FUNCTION `castDecimalAsDouble`(
decimalInput DECIMAL(65,30) ) RETURNS double
DETERMINISTIC
BEGIN
DECLARE doubleOutput DOUBLE;
SET doubleOutput = decimalInput;
RETURN doubleOutput;
END
It seems not possible to cast it to DOUBLE which brings problems if you do calculations and for example want to ROUND() a DECIMAL 12,2 in the third digit. Using ROUND(foo * bar,2) will just ignore the additional digits if your foo and bar are DECIMAL 12,2 fields.
That said you can do something like this to still make it work:
ROUND(CAST(foo AS DECIMAL(30,15)*CAST(bar AS DECIMAL(30,15)),2)
DECIMAL may save space. For example, DECIMAL(4,2) occupies only 2 bytes. FLOAT takes 4; DOUBLE takes 8.
As for the original question, simply do:
ALTER TABLE t MODIFY COLUMN c DOUBLE ...;
(The "..." should include the other stuff you already had, such as NOT NULL.)
Related
I'm using MySQL database and trying to change column precision. I need to restrict numbers to 2 zeros afrer comma. But after execute this code: $this->alterColumn(offer::tableName(), 'price', $this->double(8.2)->null()); column precision in database is empty.
Result:
What I'm doing wrong?
If you want to restrict the numbers to 2 decimal numbers you should use fixed-point type like DECIMAL(8, 2).
In migration:
$this->decimal(8, 2)
Floating point types like FLOAT and DOUBLE allows only limited ways to set precision. There is support for FLOAT(M, D) and DOUBLE(M, D) syntax in MySQL. But, it's pretty much just an alias and you will always end with 4-byte float or 8-byte double. See documentation
my sql clause:
SELECT * FROM dev_userdb.ry_usercard where UserIdentity=610528194506235115
The UserIdentity is type of varchar(64).When I execute the query,the result is not what I want,why?
The UserIdentity is type of varchar(64)
Then your query should be using quotes around the value you're querying, e.g.
...userIdentity = '601528194506235115'
The reason for the result you get is explained by the MySQL manual's description of equality comparisons:
The following rules describe how conversion occurs for comparison operations:
If one or both arguments are NULL, the result of the comparison is NULL, except for the NULL-safe <=> equality comparison operator. For NULL <=> NULL, the result is true. No conversion is needed.
If both arguments in a comparison operation are strings, they are compared as strings.
If both arguments are integers, they are compared as integers.
Hexadecimal values are treated as binary strings if not compared to a number.
If one of the arguments is a TIMESTAMP or DATETIME column and the other argument is a constant, the constant is converted to a timestamp before the comparison is performed. This is done to be more ODBC-friendly. Note that this is not done for the arguments to IN()! To be safe, always use complete datetime, date, or time strings when doing comparisons. For example, to achieve best results when using BETWEEN with date or time values, use CAST() to explicitly convert the values to the desired data type.
A single-row subquery from a table or tables is not considered a constant. For example, if a subquery returns an integer to be compared to a DATETIME value, the comparison is done as two integers. The integer is not converted to a temporal value. To compare the operands as DATETIME values, use CAST() to explicitly convert the subquery value to DATETIME.
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.
Your comparison ends up using that lat rule, floating-point number comparison.
The floating-point numbers used by MySQL are IEEE-754 single-precision ("float") or double-precision ("double") binary floating point; presumably it's using doubles for the above (you'd think they'd say).
IEEE-754 double-precision binary floating point only has roughly 15 digits of decimal precision. Specifically, only some integers greater than 9007199254740992 can be represented (9007199254740993 cannot be, for instance); 601528194506235115 is well into the range where there are large gaps between representable integers. If you try to store 601528194506235115 in a double, the value you get is 601528194506235100; that's also what you get when you try to store 601528194506235117 and 601528194506235118 in doubles. So after '601528194506235117', '601528194506235118', and 601528194506235115 are all converted to doubles in order to compare them in your query, they're all 601528194506235100, and so they're all equal. (FWIW, the next representable integer after 601528194506235100 is 601528194506235300.)
JavaScript's numbers are also doubles, so we can see the effect using JavaScript here on site:
var table = [
'42',
'754',
'601528194506235117',
'601528194506235118',
'27'
];
var matches = table.filter(function(num) {
return +num === 601528194506235115;
});
console.log("matching entries:");
console.log(matches);
UserIdentity type is varchar(64), so you should use quotes around the value.
select * from table_name where UserIdentity = 'value';
I have a simple float column, that doesn't yield the correct value when selected via a CASE:
SELECT my_column FROM my_table LIMIT 1; yields 815.35
But SELECT (CASE WHEN true THEN my_column ELSE 0 END) AS my_column FROM my_table LIMIT 1; yields 815.3499755859375
Problem is obviously coming from the case and from the ELSE value (using 'test' rather than 0 works as intended, but using an other float does not)
I could solve it by using ROUND(my_column,2), or using a decimal column instead of a float one, but I'd actually want to understand what's happening here
I think #dasblinkenlight has explained the underlying issue with the representation. Your question is also about the CASE.
A CASE expression returns a single type. MySQL has to decide on the type when the query is compiled.
Your CASE is combining two different types, a float and an int. I believe that this should be returning a float value.
The rules leave me a bit confused as to why anything is happening; after all, a float to a float sounds like a no-op. But, there are two representations for floats, 4-byte and 8-byte. My guess is that your column is stored as a 4-byte float. The SQL engine decides that the CASE expression should return an 8-byte double. The conversion to the double is the cause of your issue.
In fact, this little SQLFiddle confirms this guess. The issue is a conversion to double.
The value 815.35 has no exact representation as IEEE-754 float. The value that is actually stored in a float field is an approximation that depends on the number of bits used for the representation.
When you use single-precision float, the value becomes 815.3499755859375, which is what you see printed when you run the query. You can compute the representation that you get with an IEEE-754 calculator (for example, this one).
In order to avoid representation differences like this, use decimal data ty[e to represent values that need precise decimal representation, such as amounts of money.
Hello in my database I have a column with numbers such as 6.251543423 I want to make them like 6.25 without rounding them.
I've tried update examresults set point = substring(point,0,5) but it returned all values as zero
If you don't want to round you must truncate:
TRUNCATE(6.251543423,2)
When you CAST as DECIMAL(n,2) or FLOAT(n,2) the result will be rounded.
Convert the floating point values to DECIMAL datatype, with appropriate number of digits after the decimal point. In this example, two digits after the decimal point.
SELECT CONVERT(float_col,DECIMAL(65,2)) AS dec_col
FROM ...
The floating point types FLOAT and DOUBLE are approximate decimal values. They are stored in standard IEEE floating point representation.
If you convert to decimal, and then store that back in a floating point column, it will be converted back into floating point representation.
You would need to do the conversion to DECIMAL when you pull the value back out again.
If you want to store an exact decimal representation, you would need to store the value in a column defined as DECIMAL (or NUMERIC) datatype, not a FLOAT or DOUBLE.
Also...
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,
(that's excerpted from MySQL Reference Manual: https://dev.mysql.com/doc/refman/5.5/en/floating-point-types.html )
(NOTE: I've never exercised/tested that behavior of DOUBLE(18,2). When we need exact decimals, we use DECIMAL. And when we need floating point, we use plain old DOUBLE.)
I created a table, which are contains some double, but when I added this number
7.341270020834490e+005
and the database is the following number:
734127.002083
cutting out some useful information. I want the hole number not just part of that
like:
734127.0020834490
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.
See the manual
You can store this as a string in your database....
and when you want to use the value just use some method in the language that you are using to convert string to double.