Why MySQL automatically converts strings to numbers? [duplicate] - mysql

This question already has answers here:
Select matches beginning numbers of string on integer
(2 answers)
Closed 4 years ago.
When I try compare this 65 = '65ae3ee2-aeb2-427f-8381-56db91b94363' mysql returns true, why?
SELECT query * FROM families
WHERE id = '65ae3ee2-aeb2-427f-8381-56db91b94363'
OR fam_code = '65ae3ee2-aeb2-427f-8381-56db91b94363'
returns two records:
id fam_code
65 c648b66e-ae0c-467b-af56-1e6d3c214f2e
92 65ae3ee2-aeb2-427f-8381-56db91b94363
Why is that?

In order to compare numbers with strings, MySQL converts both values to real numbers (stored used the floating-point standard).
The rules are described in the "Type Conversion in Expression Evaluation" documentation page:
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. [...]
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.
The case you described fits into the last item: "in all other cases, the arguments are compared as floating-point (real) numbers".

It returns these two records, why is that?
Because that's how MySQL tries to cast strings to numbers (to check against your integer id). Basically, it reads as much number as it can, and throws the rest away.
65ae3ee2-aeb2-427f-8381-56db91b94363
^^
Can interpret this as a number.
65ae3ee2-aeb2-427f-8381-56db91b94363
^
Garbage starts. Ignore this and the rest of the string.

Related

Yii2: problems with findOne query on float value

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)

Why does mysql 'select where clause' query wrongly?

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';

Is it possible to cast a DECIMAL to DOUBLE in MySQL?

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.)

Inserting hex value in MySQL

I have created an SQL database using Java. I have a table created which has two columns, the first being a big integer which increments, the second I have tried defining it as a char, varchar and binary.
But I'm still not getting the desired functionality. Say I try and store a hex number 0a into the char column and I get an error. I appended 0x to the beginning and it seems to store, but when I print out the contents it is blank. Or in some cases I get characters such as '/' or '?'. I also tried using SQL explorer and it gives me the same result viewing the table,
My problem is I need to store an eight character hex string such as eb8d4ee6.
Could someone please advise me of how this can be done?
See http://dev.mysql.com/doc/refman/5.5/en/hexadecimal-literals.html
MySQL supports hexadecimal values,
written using X'val', x'val', or 0xval
format, where val contains hexadecimal
digits (0..9, A..F). Lettercase of the
digits does not matter. For values
written using X'val' or x'val' format,
val must contain an even number of
digits. For values written using 0xval
syntax, values that contain an odd
number of digits are treated as having
an extra leading 0. For example, 0x0a
and 0xaaa are interpreted as 0x0a and
0x0aaa.
In numeric contexts, hexadecimal
values act like integers (64-bit
precision). In string contexts, they
act like binary strings, where each
pair of hex digits is converted to a
character:
You probably should store the Hex number in an integer column. You can then convert back to hex when selecting using the HEX() function.
E.g.,
INSERT INTO MyTable (`MyIntegerColumn`) VALUES (0xeb8d4ee6);
You can use a Json column:
And use JSON.stringify(hex) to insert and you can always get the result via select and compare too

Rules for MySQL type conversion

I'm wondering what the rules are for mysql type conversions are. e.g.
select foo/2 from table seems to yield a decimal if the foo column is an int. select sum(foo) from table gives the sum(foo) column back as a double if foo is a float. select i*i from table gives a bigint if i is an int.
What are the rules for the type conversion here when using common operators such as +-/* or aggregates such as sum/avg ?
The rules of type conversion are quite straightforward. Quoting from the MySQL Manual :: Type Conversion in Expression Evaluation:
When an operator is used with operands of different types, type conversion occurs to make the operands compatible. Some conversions occur implicitly.
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.
In all other cases, the arguments are compared as floating-point (real) numbers.
In the case of arithmetic operators, the result is determined according to the following rules. Quoting from the MySQL Manual :: Arithmetic Operators
In the case of -, +, and *, the result is calculated with BIGINT (64-bit) precision if both arguments are integers.
If one of the arguments is an unsigned integer, and the other argument is also an integer, the result is an unsigned integer.
If any of the operands of a +, -, /, *, % is a real or string value, the precision of the result is the precision of the argument with the maximum precision.
In division performed with /, the scale of the result when using two exact values is the scale of the first argument plus the value of the div_precision_increment system variable (which is 4 by default). For example, the result of the expression 5.05 / 0.014 has a scale of six decimal places (360.714286).
Then for aggregate functions, the following applies. Quoting from the MySQL Manual :: Aggregate Functions:
For numeric arguments, the variance and standard deviation functions return a DOUBLE value. The SUM() and AVG() functions return a DECIMAL value for exact-value arguments (integer or DECIMAL), and a DOUBLE value for approximate-value arguments (FLOAT or DOUBLE).