Hope you all are doing well.
Today morning I was writing some sql query and I found a situation where I need your suggestion on that so here is the situation:
I've a table in mysql called users it has id column which is bigint
now when I'm trying to extract data with a query like :
select * from users where id = 123
in this case it'll show the result for user 123
now the situation here is if I run the same query like:
select * from users where id = 123b
now the issue here is it is still giving me the data for user 123
need your suggestion guys on the same, I did some R&D on the same but didn't found much usefull.
Thank you
Your question is tagged with mysqli which means you are using PHP to build your query. If you pass the string 123b as an integer, PHP will keep the leading digits:
var_dump((int)'123b');
# output: int(123)
MySQL then execute your query with this well formed integer 123.
If you execute a raw SQL query using any tool of your choice you should get an error like the following:
Unknown column '123b' in 'where clause'
This is because 123b cannot be an integer as it contains a letter, and isn't a string as it has no string delimiters.
Note that MySQL can still interpret strings without delimiters like hexadecimal values. For example, 0x31323362 is a valid string value for 123b and does not need quotes around it.
Related
I have a pretty simple table called roles:
When I ran SELECT * FROM roles WHERE role_id = "1ojosd041l"(the WHERE clause clearly didn't match with any row in the table). It somehow returned this:
Does anyone know why this is happening? My guess is that my role_id column is of type int, but I passed a string into the WHERE clause, so the str to int conversion produced something weird (like a 0 or 1).
I'm just looking for an official explanation for this. If anyone knows why this happens please let me know! Thank you!
Where MySQL expects a number, it will convert a string to a number, and ignore any leading whitespace or trailing garbage.
If you want to avoid this, do something like
SELECT * FROM roles WHERE role_id = "1ojosd041l" and concat(role_id) = "1ojosd041l"
Just the second condition would be enough but leaving the first condition in allows an index to be used.
There is somee MySQL magic happening here. MySQL sees that role_id is numeric. So it converts your string '1ojosd041l' to a number. This string isn't a number obviously, and MySQL should throw an error. But MySQL just takes as many digits as it finds from the left side of your string instead, so it gets number 1. (If your string started with a non-digit, then MySQL would even return a zero.)
This question already has an answer here:
What is going on with MySQL integer field matching string?
(1 answer)
Closed 2 years ago.
I have a table name workspaces with id has data type = bigint(20) unsigned
I'm trying to query my database as the following:
SELECT * FROM workspaces WHERE id = 1;
SELECT * FROM workspaces WHERE id = '1.a';
Both of them are returns the correct result. But I think the (2) statement is wrong, why sql still return correct value right? What is the reason?
Could you help me to understand why? Thank you so much.
Here is test case on db<>fiddle.
MySQL has complex casting rules for what happens when you try to compare a string literal (e.g. 1.a) against an integer column (id). What is happening here is that MySQL is taking the leading numbers from the string and then forming a number based on that. As a result, the check becomes 1 = 1, which is true for that particular record which is being returned.
On most other databases, your second query would not even execute, which is generally all the better for you. You should not mix numeric and non numeric types in the same comparison.
It extracts the number from string.
For example "1.a"=1
I hope it helps.
In a situation where the sides of a comparison operator (= in this case) don't match, the database will do its best to convert one side the other's type. If there's absolutely no way of doing it, it will throw an error, but it still won't be a syntax error (since the query itself has a valid form), but some error about type conversion.
MySQL, specifically, notoriously plays fast and loose with type conversions. In the case of converting a character literal to a numeric type, if the string starts with a digit, it will convert the starting sequence of digits to a number and ignore anything after it.
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'
I'm trying to replicate the following LIKE query using a full text search on JSON data;
SELECT * FROM table
WHERE response LIKE '%"prod_id": "foo"%'
AND response LIKE '%"start_date": "2016-07-13"%'
In my database the above query returns 28 rows
This is my attempt:
SELECT * FROM table
WHERE MATCH(response)
AGAINST('+"\"prod_id\": \"foo\"",+"\"start_date\": \"2016-07-13\""')
However this returns over 4,500 rows (the same as running the first query for only the prod_id ~1,900 rows when running the first query on just the date)
It was my understanding that +"text here" would indicate a required word, and that literal double quotes (present in the JSON data) should be escaped, and that , would indicate a split between the two strings I'm looking for. What am I not understanding correctly? Is there any point in running this as a full text query anyway?
Thanks to #Sevle I've tweaked my query like so, and it's returning the correct results;
SELECT * FROM table
WHERE MATCH(response)
AGAINST('+\"prod_id: foo\" +\"start_date: 2016-07-13\"' IN BOOLEAN MODE)
The comma was not helping and I was escaping the wrong characters, and of course I did need IN BOOLEAN MODE to be added. Finally, I removed the double quotes I was searching for in the JSON string.
It may also be worth noting that as I'm using PHP PDO to run this query I also had to make the following tweaks.
Instead of constructing the query like so trying to bind the variables like I normally would;
$query = $db->prepare('...AGAINST('+\"prod_id: :prod_id\" +\"start_date: :start_date\"');
$query->execute(array('prod_id' => 'foo', 'start_date' => '2016-07-13'));
I had to do this, as I found I could not bind variables in full text searches
$sql_against = $db->quote('...AGAINST('+\"prod_id: foo\" +\"start_date: 2016-07-13\"');
$query = $db->prepare("...AGAINST($sql_against IN BOOLEAN MODE)")
I have this string: alexandre.aba\40gmail.com#gtalk.ofelia.dcc.fc.up.pt stored as JabberID in USER table in my database.
The problem is when i execute this query:
SELECT * FROM `USER` WHERE JabberID='alexandre.aba\40gmail.com#gtalk.ofelia.dcc.fc.up.pt'
It returns:
MySQL returned an empty result set (i.e. zero rows).
I think it's the \40 that is causing the problem but i don't know how to fix it.
You should think about using prepared statements instead since it's safer but to correct the current string look at the link http://dev.mysql.com/doc/refman/5.1/en/string-literals.html for a list of special characters.
I think the \ should be replaced with \\