Mysql max on hex string - mysql

i am having issues using the max operator on a hex value saved in varchar(25) format.
The numbers are like this:
0
1
0A
0F
FF
10A
Now if i do something like this:
SELECT MAX(CONV(number, 16, 10)) as number FROM `numbers` WHERE 1
i get FF (255) instead of what i would expect to be 10A (266)
What's the problem? Is it with the different lengths? But why does it work for 0 and FF then? A hint would be great!
Thanks in advance.

From the documentation: http://dev.mysql.com/doc/refman/5.0/en/mathematical-functions.html#function_conv
Converts numbers between different number bases. Returns a string representation of the number N, converted from base from_base to base to_base.
The result of conv is always a string. If your to_base is 10, it will still result in a string even though you think it should make sense to be a number.
When maxing a varchar column, mysql can do some strange things, but I personally do not know all the details. Has to do with B-trees. See this resource. http://dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html. Strange that there is info on this problem at that page, but it's the cause.

Related

Need some assistance understanding binary addition/subtraction using 2's complement

If A = 01110011, B = 10010100, how would I add these?
I did this:
i.e: 01110011 + 10010100 = 100000111
Though, isn't it essentially 115 + (-108) = 7, whereas, I'm getting -249
Edit: I see that removing the highest order bit (overflow) I get 7 which is what I'm looking for but I'm not getting why you wouldn't have the extra bit.
Edit**: Ok, I figured it out. There was no overflow as I had assumed there was because 7 is within [-128, 127] (8-bits). Instead, like Omar hinted at I was supposed to drop the "extra" 1 from addition.
Your calculation is correct and the result is correct.
You stated that the second number is -108, so both your numbers are interpreted as signed 8-bit values. Thus, you should also interpret your result as an 8-bit signed value, this is why the 9th bit must be dropped, and so the result is 7 (00000111).
On a real hardware, like an 8-bit CPU for example, as all the registers are 8-bit wide, you are only be able to store the lowest 8-bit of the result, which here is 7 (00000111).
In some cases, the 9th bit may also be put inside a carry/overflow flag so it's not completely "dropped".

How can I store a number with a leading zero in mysql database?

I am trying to store the number 0.0015 in the database. I have tried float, integer but I am getting zero not the exact figure I have entered. Is there a datatype which can store such a value?
Normally you'd use DECIMAL (aka NUMERIC), with a specified scale and precision, here are the docs for it. FLOAT should also work, but you need to be aware of floating point arithmetics quirks, so DECIMAL is preferred.
Here's a dbfiddle example
If you see your data as 0 then it's either an issue with how you're inserting (maybe importing from a file) or your client rounds it down to 0 and you need to tweak it. As you can see from the dbfiddle above, it works perfectly fine.
This number (0.0015) is not representable in binary. See the following example in python:
Python 3.10.2 (tags/v3.10.2:a58ebcc, Jan 17 2022, 14:12:15) [MSC v.1929 64 bit (AMD64)] on win32
>>> x = 0.0015
>>> (x + 1) - 1
0.0015000000000000568
This means that the storing in mysql (or any other language that converts the number to binary) will show up representation errors. You can use numeric types that doesn't do any conversion to binary, like decimal or numeric.

Mysql CAST return invalid data

I have a query
SELECT MAX(CAST(user_name as SIGNED)) as max_id FROM (`users`)
it returns
2.01303045556E+12
but actually the maximum value is 2013030455555
Anybody know how it happens??
That is correct.
2.01303045556E+12 actually IS 2013030455555.
x E+12 means x*10 ^ 12
2*10^12=2000000000000 (2 followed by 12 zeros).
This is expotential (usually floating point) number representation. See Scientific notation at wikipedia (scroll down to "E notation").
To get rid of it you may cast that data to decimal or integer, instead of float. Maybe there are better methods, but I dont know them.
Example:
-- example for 16 digits
SELECT MAX(CAST(user_name as DECIMAL(16,0)) as max_id FROM (`users`)
Another solution: change format of the number in SQL or maybe PHP if you are using it.

Mysql: xor a string with a key

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.

Performing bitwise operations on large bit strings in MySQL?

I've got a MySQL database with a large amount of 2048-bit binary strings (e.g '0111001...0101'). One calculation I'll need is the Hamming Distance (the total count of 1's in the XOR'd result) of these strings compared to some externally generated bitstring. In order to get an idea of how to write this query, I tried writing it for smaller bitstrings. Here's an example:
select BIT_COUNT(bin((b'0011100000') ^ (b'1111111111')))
The inner portion that computes the XOR works correctly, but BIT_COUNT returns strange results. This example returns 14, which is longer than the string itself.
So I have a few questions:
First, why is BIT_COUNT returning such strange results. Is it operating on a string rather than the binary string I'd like it to operate on? If so, how do I deal with this?
Second, notice that I'm casting (is that the right word here?) the strings as binary by prepending with a b. How would I do this with column names and variables? Clearly I can't simply prepend a b to a variable name, and I can't insert a space between. Any ideas?
Thanks,
EDIT:
So here's a solution to the first problem:
select BIT_COUNT(b'0011100000' ^ b'1111111111')
There seems to be a problem when using this for larger strings (2048 bits). I tried:
select BIT_COUNT(b'001110...00011')
and it gives me results like 28, when the actual bitcount should be around 1024. If I remove the b, then it appears to max-out at 64. Any ideas on how to resolve this problem?
Just remove bin function. With it BIN_COUNT treats its argument as a chars string, not as a set of bits. So
select BIT_COUNT(b'0011100000' ^ b'1111111111')
will do the work