I have this fragment of MSSQL -
CONVERT(INT, HASHBYTES('MD5', {some_field}))
...and I'd really like a MySQL equivalent. I'm pretty sure the HASHBYTES('MD5', ...) bit is the same as MySQL's MD5(...) - it's the CONVERT(INT, ...) bit that's really puzzling me.
Thanks.
From the MySQL manual entry for the MD5() function:
The value is returned as a string of 32 hex digits, or NULL if the argument was NULL.
The MSSQL CONVERT() function which you quote above converts its varbinary argument to a signed 32-bit integer by truncating to the 4 lowest-order bytes. This is a bit of a nuisance because MySQL arithmetic works to 64-bit precision.
We must therefore take the rightmost 8 digits of MySQL's hex representation (representing the 4 lowest-order bytes) and convert to decimal using MySQL's CONV() function, then sign-extend the result:
CONV(RIGHT(MD5('foo'),8), 16, 10) ^ 0x80000000 - 0x80000000
Related
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.
I am running a command similar to this in mysql 5.6:
SELECT pow(2, 87) FROM `table`
And the results are always shown in scientific notation, and when trying to CAST it to a decimal I am losing all the precision. Is there a way to simply output the full decimal value of this equation?
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.)
I want to Bitwise-XOR a string (actually its binary representation) with a KEY.
The result of the operation should be represented as HEX.
What I have:
'a' - the UTF-8 String to be changed.
'ACF123456' - the key in HEX.
Result seen as BIGINT:
select CONV(HEX('a'), 16, 10) ^ CONV('ACF123456', 16, 10);
Result seen as HEX:
select CONV( CONV(HEX('a'), 16, 10) ^ CONV('ACF123456', 16, 10), 10, 16);
Questions:
Is the conversion above done correctly?
What happens if the string is too long (i.e instead of 'a' we have 'a veeeeeery long string')? It seems that the conv() function has a limitation (is it the 64-bit precision from the documentation)? And besides the XOR operator ^ has also a limitation, related to the nr. of bits of the returned result. Any solutions that work for any string (a stored procedure is allowed)?
Thanks.
Your conversions look fine to me.
And as you point out, both CONV() and ^ have indeed a 64-bits precision.
2^64 = 16^16, therefore strings of more than 16 hexadecimal digits should convert to integers larger than 2^64. However, such strings will be brutally (silently) truncated from the left when attempting to convert them to integers.
The point of my solution here is to slice such strings. Obviously, the result may not be displayed as an integer, but only as a string representation.
Let #input be your "string to be changed" and #key, your "key".
Assign HEX(#input) to #hex_input. No problem here since HEX() works with strings.
Slice #hex_input into 16 hexadecimal digit long strings, starting from the right
Likewise, slice #key into 16 digit long strings.
Compute the X-OR of each 64-bit slice of #hex_input with each 64-bit slice of #key, starting from the right. Use CONV(#slice, 16, 10). If either #hex_input or #key has less slices than the other string, then X-OR the remaining slices of the other string with 0.
Convert each 64-bit number resulting from the X-OR in point 4. back into an hexadecimal string with UNHEX().
Reassemble the resulting slices. This is your result.
A three-columns TEMPORARY table could be used as an array to store slices of #hex_input, #mask and the resulting slices.
Put this all together into a stored procedure, and voilĂ !
You sound like you have some skills in MySQL, you should be able to translate the above into real code. But I'll be happy to help if you need further guidance.
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).