SQL SELECT is selecting rows that do not match the query - php

I am using php mysql_query() to select rows from my SQL Database but for some reason it is selecting rows that do not match the query. For example:
mysql_query("SELECT * FROM Table WHERE ID='153'")
This will return the row who has an ID of 153
but so will:
mysql_query("SELECT * FROM Table WHERE ID='153c'")
Am I doing something wrong?

As noted, the issue is comparing a string value to an integer value. Your expression is:
WHERE ID = '153' and
WHERE ID = '153a'
You can imagine the MySQL engine describing what it does as: "id is an integer column. So, I need to compare it to an integer value. Oh, the right side is a string, so I will convert the right hand side to an integer."
The way that MySQL converts values to a number from a string could be called "silent conversion". It converts the longest leading number that it finds, and then stops. If there is no leading number (say 'a123'), then the value is 0. There is no error produced.
If you really want to confuse yourself, consider the following:
select (case when 123 = '123e' then 1 else 0 end),
(case when 123 = '123e3' then 1 else 0 end),
(case when 123 = '123a' then 1 else 0 end),
(case when 123 = '123a3' then 1 else 0 end)
This returns: true, false, true, and true. Why is the second one false, but the others true? Well, '123e3' is interpreted as scientific notation, so the value becomes 123,000. For all the others, the conversion stops at the first alphabetic character.
As mentioned in the other answers, the obvious fix is to drop the single quotes on the constant.

Why are you passing the ID value as a String? This would most likely be your issue. Try passing the following query instead:
mysql_query("SELECT * FROM Table WHERE ID= 153")
This way, the ID value being searched for is an int (or any other primitive the ID column is set to). This should restrict the IDs properly. In addition, if you are creating IDs with numbers, it's best practice to use distinct ints only and not strings.

Related

MySQL updates all rows when the column name is only specified in the where clause

It's been a while I didn't work on mysql and I was suprised to see that the following statement is valid:
UPDATE table_A
SET col_a = value
WHERE id;
It looks like MySQL updates all rows in the table. I have a good MSSQL background and I am trying to understand why this valid in MySql?
Also, I ran a query with a similar where clause on a varchar column:
SELECT distinct description
FROM table_A
where NOT description;
I tought it will return only null or empty values. Instead, it returns lots of rows with non-null values.
Any ideas why?
Thanks,
WHERE x will match any rows for which x evaluates to a truthy value. Since BOOLEAN is actually a number type TINYINT(1), this works by converting to a number and then comparing to zero - any nonzero number is truthy. (NULL is falsy.)
If you write WHERE id = 123, then only for the row where id is 123, the expression id = 123 will evaluate to TRUE (which is the same as 1) and it will match, otherwise it will evaluate to FALSE (0).
But if you write WHERE id, the requirement is that id evaluates to a truthy value. If id is a number, only IDs 0 and NULL will be falsy.
However, in case of description, you have a string. And the string is first converted to a number. The reason you got many results there is that any string that starts with a number (that is nonzero) is matching, such as 01234hello (which converts to 1234, which is nonzero). Check what CONVERT(description, SIGNED) gives - if it is nonzero, then it matches.
This is why, when building AND or OR queries in code, you can avoid handling the case of zero conditions specially by starting with TRUE or 1 (in the AND case) or FALSE or 0 (in the OR case), since WHERE TRUE/WHERE 1 is valid (matches everything), as is WHERE FALSE/WHERE 0 (matches nothing). So you build a query by starting with WHERE 1 and adding to it: WHERE 1, WHERE 1 AND id = 123, WHERE 1 AND id = 123 AND type = 'xy', etc.

MySQL Query - replace or remove 0 (zero) in a column, but not remove the digit zero in a word or number?

I have a table where one column has 0 for a value. The problem is that my page that fetches this data show's the 0.
I'd like to remove the 0 value, but only if it's a single 0. And not remove the 0 if it's in a word or a numeric number like 10, 1990, 2006, and etc.
I'd like to see if you guys can offer a SQL Query that would do that?
I was thinking of using the following query, but I think it will remove any 0 within a word or numeric data.
update phpbb_tree set member_born = replace(member_born, '0', '')
Hopefully you guys can suggest another method? Thanks in advance...
After discussed at the comments you have said that you want to not show 0 values when you fetching the data. The solution is simple and should be like this.
lets supposed that you have make your query and fetch the data with a $row variable.
if($row['born_year'] == '0'){
$born_year = "";
} else {
$born_year = $row['born_year'];
}
Another solution is by filtering the query from the begging
select * from table where born_year !='0';
update
if you want to remove all the 0 values from your tables you can do it in this way. Consider making a backup before.
update table set column='' where column='0';
if the value is int change column='0' to column=0

ID number zero, one, o and i in query

We have a system that creates a 5 digit alpha-numeric string of numbers and letters. Originally, I had the full alphabet and 0-9 so something like the following was possible:
0O1I0
Because different fonts may be used on different systems, there was confusion between the o's and i's so I updated the function to only include the numbers. Because there are historical items with the "o" and "i" items I have been asked to modify our search to automatically look for a zero if an o is entered and a 1 if an i is entered (or vice versa).
These are 5 digit ids with 2 possible values for the specific character. I'm thinking I could loop over the value with PHP prior to writing the query to build a list of options and then check if "IN (list of items)" in my query. I don't know if there's something built in that I'm missing though in MySQL like..
WHERE ID = o/0, i/1, etc.
So how about parsing the id in php, replacing every occurence of 0 or O with regex string [o0], and similarly replacing i and 1 with [i1].
Then you could use this string in your query like this
WHERE id REGEXP '...[i1]...[o0]...'
The php code could look like this
$id = '0O1I0';
$id = preg_replace('/[i1]/i', '[i1]', $id);
$id = preg_replace('/[o0]/i', '[o0]', $id);
echo $id; // [i1][o0][i1][o0][o0]
...
mysqli_query($conn, "SELECT ... WHERE id REGEXP '$id'");
What about something like
select <stuff> from <table>
where replace(replace(upper(id), 'I', '1'), 'O', '0') like '%<number-search-term>%'
EDIT (more detail)
replace() in mysql takes three arguments: the original term, what to look for, and what to swap it with. In the where clause I did a nested replace. The inner one replaced any instances of I with 1 and the outer one took the inner replace as its argument (so with all Is as 1s) and replaced any Os with 0s. This is then compared against the number search term (I used a like statement).

Perform partial search on MySQL table when exact match may be available

I am running the following SQL statement from a PHP script:
SELECT PHONE, COALESCE(PREFERREDNAME, POPULARNAME) FROM distilled_contacts WHERE PHONE LIKE :phone LIMIT 6
As obvious, the statement returns the first 6 matches against the table in question. The value I'm binding to the :phone variable is goes something like this:
$search = '%'.$search.'%';
Where, $search could be any string of numerals. The wildcard characters ensure that a search on, say 918, would return every record where the PHONE field contains 918:
9180078961
9879189872
0098976918
918
...
My problem is what happens if there does exist an entry with the value that matches the search string exactly, in this case 918 (the 4th item in the list above). Since there's a LIMIT 6, only the first 6 entries would be retrieved which may or may not contain the one with the exact match. Is there a way to ensure the results always contain the record with the exact match, on top of the resulting list, should one be available?
You could use an order by to ensure the exact match is always on top:
ORDER BY CASE WHEN PHONE = :phone THEN 1 ELSE 2 END
Using $search = ''.$search.'%' will show result, that matches the starting value.

MySQL select only using first word of variable

I am using php and mySQL. I have a select query that is not working. My code is:
$bookquery = "SELECT * FROM my_books WHERE book_title = '$book' OR book_title_short = '$book' OR book_title_long = '$book' OR book_id = '$book'";
The code searches several title types and returns the desired reference most of the time, except when the name of the book starts with a numeral. Though rare, some of my book titles are in the form "2 Book". In such cases, the query only looks at the "2", assumes it is a "book_id" and returns the second entry in the database, instead of the entry for "2 Book". Something like "3 Book" returns the third entry and so forth. I am confused why the select is acting this way, but more importantly, I do not know how to fix it.
If you have a column in your table with a numeric data type (INT, maybe), then your search strategy is going to work strangely for values of $book that start with numbers. You have discovered this.
The following expression always returns true in SQL. It's not intuitive, but it's true.
99 = '99 Luftballon'
That's because, when you compare an integer to a string, MySQL implicitly does this:
CAST(stringvalue AS INT)
And, a cast of a string beginning with the text of an integer always returns the value of the integer. For example, the value of
CAST('99 Luftballon' AS INT)
is 99. So you'll get book id 99 if you look for that search term.
It's pointless to try to compare an INT column to a text string that doesn't start with an integer, because CAST('blah blah blah' AS INT) always returns zero. To make your search strategy work better, you should consider omitting OR book_id = '$book' from your search query unless you know that the entirety of $book is a number.
As others mention, my PHP allowed both numerical enties and text entries from the browser. My query was then having a hard time with this, interpreting some of my text entries as numbers by truncating the end. Thus, my "2 Book" was being interpreted as the number "2" and then being queried to find the second book in the database. To fix this I just created a simple if statement in PHP so that my queries only looked for text or numbers. Thus, in my case, my solution was:
if(is_numeric($book)){
$bookquery = "SELECT * FROM books WHERE book_id = '$book'";
}else{
$bookquery = "SELECT * FROM books WHERE book_title = '$book' OR book_title_short = '$book' OR book_title_long = '$book'";
}
This is working great and I am on my way coding happily again. Thanks #OllieJones and others for your questions and ideas which helped me see I needed to approach the problem differently.
Not sure if this is the correct answer for you but it seems like you are searching for only exact values in your select. Have you thought of trying a more generic search for your criteria? Such as...
$bookquery = "SELECT * FROM my_books WHERE book_title LIKE '".$book."' OR book_title_short LIKE '".$book."' OR book_title_long LIKE '".$book."' OR book_id LIKE '".$book."'"
If you are doing some kind of searching you might even want to ensure the characters before the search key are found as well like so....
$bookquery = "SELECT * FROM my_books WHERE book_title LIKE '%".$book."' OR book_title_short LIKE '%".$book."' OR book_title_long LIKE '%".$book."' OR book_id LIKE '%".$book."'"
The % is a special char that looks for allows you to search for the chars you want to search for PLUS any characters before this that aren't in the search criteri... for example $book = "any" with a % before hand in the query like so, '%".$book."'"`` would return bothcompanyand also the wordany` by itself.
If you need to you can add a % to the end also like so, `'%".$book."%'"`` and it would do the same for the beginning and end of the search key

Categories