In a database (MySql) I am storing some string values and checking for the uniqueness of those strings before storing them.
For a fast string comparison (I mean check if the incoming string already exists in the DB before recording) I want to hast the incoming string (MD5), split the string into 2 equal parts, convert them into 2 bigints, store them separately along with the string, and when a record request arrives I want to search for these 2 bigints in a multiple column index. (ofcourse i will get the incoming string, MD5 that string, calculate the 2 bigint parts then query the database)
But the "line 3" below produces an interesting error in my "MySql Routine".
...
declare mystring varchar(3000); -- line 1
declare md5bigint1value bigint; -- line 2
...
set md5bigint1value = conv(substring((md5(mystring)),1,16),16,10); -- line 3
...
At "line 3" it says: Error Code: 1264. Out of range value for column 'md5bigint1value' at row 1
Does anybody know why this is happening?
Please let me know if you need any more info.
Thank you very much.
CONV, when used with a positive to_base, converts to an unsigned value, while BIGINT is signed. An unsigned 64-bit value won't necessarily fit into a signed 64-bit variable.
If to_base is a negative number, N is regarded as a signed number. Otherwise, N is treated as unsigned.
What you want to do is use -10 for a destination base, that is;
set md5bigint1value = conv(substring((md5(mystring)),1,16),16,-10); -- line 3
SQLfiddle to test with (10 won't work, -10 will).
Related
I have a simple table using a non auto inc INT as primary key.
When querying the table with condition e.g. WHERE id='2,5,6' (unintentionally!) it returns a result set!
Ok, it works, but why?
id is an integer and you compare it with a string '2,5,6'. MySQL converts the string to a number in order to compare the two.
Well, '2,5,6' isn't a number and other DBMS would throw an error. But MySQL uses another approach: it converts character per character until the string is ended or the character is not numeric. So it sees the 2 then the comma. Depending on your settings the comma is the dicimal separater or not. So MySQL either converts to 2 or to 2.5.
Here is the documentation on implicit conversions in MySQL: https://dev.mysql.com/doc/refman/5.5/en/type-conversion.html.
The algorithm on how to convert a string to a number is not explicitly described there, but they say for instance
there are many different strings that may convert to the value 1, such as '1', ' 1', or '1a'.
They also point out in that document that implicit conversion is dangerous, because strings are not converted to DECIMAL (as I would have thought), but to the approximate datatype DOUBLE. So in MySQL we should always avoid implicit conversion from string to number.
I have a decimal field in my MySQL database. I have defined it as this:
decimal(1,1) UNSIGNED NULL. But I would like to set a default value for it like 7.0, and this is the problem I have. Whenever I want to set this value, I get this error:
Invalid default value ...
I also tried to set it as 7,0 and 7 but it resulted the same error. What is the correct default value for a MySQL decimal field?
Note: I am using Navicat for MySQL
In MySQL, when declaring DECIMAL(P,S) :
The precision (P) represents the number of significant digits that are stored for values, and the scale (S) represents the number of digits that can be stored following the decimal point.
So in your example, DECIMAL(1,1) means at most 1 digit, and at most 1 digit after the dot... which doesn't really make sense.
To better understand, here are more examples:
DECIMAL(5,2): 5 digits, two of them being used for the fractional part. Hence, possible values range from -999.99 to 999.99
DECIMAL(5,0): no fractional part allowed, so it is equivalent to an integer with maximum 5 digits.
With UNSIGNED, the behavior is the same, but using a minus sign will throw an error.
Can anyone help me understand the following problem with a BIT(64) column in MySQL (5.7.19).
This simple example works fine and returns the record from the temporary table:
CREATE TEMPORARY TABLE test (v bit(64));
INSERT INTO test values (b'111');
SELECT * FROM test WHERE v = b'111';
-- Returns the record as expected
When using all the 64 bits of the column it no longer works:
CREATE TEMPORARY TABLE test (v bit(64));
INSERT INTO test values (b'1111111111111111111111111111111111111111111111111111111111111111');
SELECT * FROM test WHERE v = b'1111111111111111111111111111111111111111111111111111111111111111';
-- Does NOT return the record
This only happens when using a value with 64 bits. But I would expect that to be possible.
Can anyone explain this to me?
Please do not respond by advising me not to use BIT columns. I am working on a database tool that should be able to handle all the data types of MySQL.
The problem seems to be, that the value b'11..11' in the WHERE clause is considered to be a SIGNED BIGINT which is -1 and is compared to the value in your table which is considered to be an UNSIGNED BIGINT which is 18446744073709551615. This is always an issue when the first of 64 bits is 1. IMHO this is a bug or a design flaw, because I expect an expression in the WHERE clause to match a row if the same expression has been used in the INSERT satement (at least in this case).
One workaround would be to cast the value to UNSIGNED:
SELECT *
FROM test
WHERE v = CAST(b'1111111111111111111111111111111111111111111111111111111111111111' as UNSIGNED);
Or (if your application language supports it) convert it to something like long uint or decimal:
SELECT * FROM test WHERE v = 18446744073709551615;
Bits are returned as binary, so to display them, either add 0, or use a function such as HEX, OCT or BIN to convert them https://mariadb.com/kb/en/library/bit/ or Bit values in result sets are returned as binary values, which may not display well. To convert a bit value to printable form, use it in numeric context or use a conversion function such as BIN() or HEX(). High-order 0 digits are not displayed in the converted value. https://dev.mysql.com/doc/refman/8.0/en/bit-value-literals.html
I have a table on my MySQL db named membertable. The table consists of two fields which are memberid and membername. The memberid field has the type of integer and uses auto_increment function starting from 2001. The membername table has the type of varchar.
The membertable has two records with the same order as described above. The records look like this :
memberid : 2001
membername : john smith
memberid : 2002
membername : will smith
I found something weird when I ran a SELECT statement against the memberid field. Running the following statement :
SELECT * FROM `membertable` WHERE `memberid` = '2001somecharacter'
It returned the first data.
Why did that happen? There's no record with memberid = 2001somecharacter. It looks like MySQL only search the first 4 character (2001) and when It's found related data, which is the returned data above, it denies the remaining characters.
How could this happen? And is there any way to turn off this behavior?
--
membertable uses innodb engine
This happens because mysql tries to convert "2001somecharacter" into a number which returns 2001.
Since you're comparing a number to a string, you should use
SELECT * FROM `membertable` WHERE CONVERT(`memberid`,CHAR) = '2001somecharacter';
to avoid this behavior.
OR to do it properly, is NOT put your search variable in quotes so that it has to be a number otherwise it'll blow up because of syntax error and then in front end making sure it's a number before passing in the query.
sqlfiddle
Your finding is an expexted MySQL behaviour.
MySQL converts a varchar to an integer starting from the beginning. As long as there are numeric characters wich can easily be converted, they are icluded in the conversion process. If there's a letter, the conversion stops returning the integer value of the numeric string read so far...
Here's some description of this behavior on the MySQL documentation Site. Unfortunately, it's not mentioned directly in the text, but there's an example which exactly shows this behaviour.
MySQL is very liberal in converting string values to numeric values when evaluated in numeric context.
As a demonstration, adding 0 causes the string to evaluated in a numeric context:
SELECT '2001foo' + 0 --> 2001
, '01.2-3E' + 0 --> 1.2
, 'abc567g' + 0 --> 0
When a string is evaluated in a numeric context, MySQL reads the string character by character, until it encounters a character where the string can no longer be interpreted as a numeric value, or until it reaches the end of the string.
I don't know of a way to "turn off" or disable this behavior. (There may be a setting of sql_mode that changes this behavior, but likely that change will impact other SQL statements that are working, which may stop working if that change is made.
Typically, this kind of check of the arguments is done in the application.
But if you need to do this in the SELECT statement, one option would be cast/convert the column as a character string, and then do the comparison.
But that can have some significant performance consequences. If we do a cast or convert (or any function) on a column that's in a condition in the WHERE clause, MySQL will not be able to use a range scan operation on a suitable index. We're forcing MySQL to perform the cast/convert operation on every row in the table, and compare the result to the literal.
So, that's not the best pattern.
If I needed to perform a check like that within the SQL statement, I would do something like this:
WHERE t.memberid = '2001foo' + 0
AND CAST('2001foo' + 0 AS CHAR) = '2001foo'
The first line is doing the same thing as the current query. And that can take advantage of a suitable index.
The second condition is converting the same value to a numeric, then casting that back to character, and then comparing the result to the original. With the values shown here, it will evaluate to FALSE, and the query will not return any rows.
This will also not return a row if the string value has a leading space, ' 2001'. The second condition is going to evaluate as FALSE.
When comparing an INT to a 'string', the string is converted to a number.
Converting a string to a number takes as many of the leading characters as it can and still be a number. So '2001character' is treated as the number 2001.
If you want non-numeric characters in member_id, make it VARCHAR.
If you want only numeric ids, then reject '200.1character'
This is more a "why" or "any pointers to documentations" question.
Today I realised that a comparison in WHERE clause takes only the first numerical part of the string if compared to an INT column. (My own conclusion)
For example:
SELECT * FROM companies c WHERE id = '817m5'
will still return companies with id = 817.
It does make sense but I'm failing to find this documented anywhere to see if my conclusion is correct and if there are additional things to know about this exact behaviour. WHERE, INT type, comparison documentation? Where? How is it called?
Thanks!
This is the comparison:
WHERE id = '817m5'
and id is an integer.
So, MySQL has to compare an integer to a string. Well, it can't do that directly. It either has to convert the string to a number or the number to the string. MySQL converts the string to a number, which it does by converting the leading numeric characters. So, the '817m5' becomes 817.
Here is the exact quote:
To cast a string to a numeric value in numeric context, you normally
do not have to do anything other than to use the string value as
though it were a number:
mysql> SELECT 1+'1'; -> 2