Why comparing Strings in MySQL query is not working - php

I am running a very simple SELECT query in MySQL and it's not working.
SELECT string_name FROM table_name;
This is giving me required output. Like
This is string one.
This is string two.
This is string three.
and so on...
But if I am running a query like this
SELECT * FROM table_name WHERE string_name='This is string one'
It's not giving any output. I even tried TRIM function.
SELECT * FROM table_name WHERE TRIM(string_name)=TRIM('This is string one')
But it's still not giving any output.
Please suggest what I am missing here. Is it because of some formatting or am I doing any silly mistake. By the way, Strings are saved as VARCHAR in the database.

To reiterate from comments; sometimes "non-printing" control characters (like newlines) can make their way into data they were never intended to be a part of. You can test for this by checking CHAR_LENGTH of field values versus what you actually see. Obviously, on large amounts of data this can be difficult; but if you know of one problematic value already, you can use this method to confirm this is the problem on that row before attempting to identify the offending character.
Once this problem is confirmed, you can use queries with MySql's ASC() and substring functions to identify character codes until you find the character; it can be best to start from the end of the string and work back, as often the offending characters are at the end.
The character or characters identified in known problem rows are often the cause of other problem rows as well, so identifying the issue in one known row can actually help resolve all such problems.
Once the character code(s) are identified, queries like WHERE string_name LIKE CONCAT('%', CHAR(13), CHAR(10)) should work (in this case for traditional Windows newlines) to identify other similar problem rows. Obviously, adjust character codes and wildcards according to your circumstances.
If no row should ever have those characters anywhere, you should be able to clean up the data with an update like this:
UPDATE theTable SET theString = REPLACE(REPLACE(theString, CHAR(10), ''), CHAR(13), '') to remove the offending characters. Again, use the codes you've actually observed causing the problem; and you can convert them to spaces instead if circumstances are better handled that way, such as a newline between two words.

Have you tried using LIKE for debugging purposes?
SELECT * FROM table_name WHERE string_name LIKE 'This is string one'
/!\ Don't just switch from = to LIKE, read about why here
TLDR:
= is apparently 30x faster.
Use = wherever you can and LIKE wherever you must.

First of all, I must acknowledge the points made by #Uueerdo were actually the the main cause of this issue. Even I was somewhat sure that there are some hidden characters in the string causing all the issue but I was not sure how to find and fix that offending character.
Also, the approach suggested by #Uueerdo to check and replace the offending character using the ASCII code seems quite legit but as he himself mentioned that this process will take lot's of time and one have to manually check every string for that one offending character and then replace it.
Luckily after spending couple of hours on it, I came up with a much faster approach to fix the issue. For that, first of all I would like to share my use case.
My first query was for selecting all the strings from a database and printing the result on page.
$result = mysqli_query($conn, "SELECT * from table_name");
while($row = mysqli_fetch_array($result)){
$string_var = $row["string_name"];
echo $string_var;
echo "<br>";
}
The above code was working as expected and printing all the string_name from the table. Now, if I wanted to use the variable $string_var for another SELECT query in the same table, it was giving me 0 results.
$result = mysqli_query($conn, "SELECT * FROM table_name");
while($row = mysqli_fetch_array($result)){
$string_var = $row["string_name"];
echo "String Name : ".$string_var."";
$sec_result = ($conn, "SELECT * FROM table_name WHERE string_var='$string_name'");
if(mysqli_num_rows($sec_result) > 0){
echo "Has Results";
} else {
echo "No Results";
}
}
In this snippet, my second query $sec_result was always giving me No Results as output.
What I simply did to fix this issue.
$result = mysqli_query($conn, "SELECT * FROM table_name";
while ($row = mysqli_fetch_array($result)){
$string_var = $row["string_name"];
$row_id = $row["id"];
$update_row = mysqli_query($conn, "UPDATE table_name SET string_name='$string_var' WHERE id=$row_id");
}
This step updated all the strings from the table without any hidden/problem causing character.
I am not generalising this approach and I am not sure if this will work in every use case but it helped me fix my issue in less than a minute.
I request #Uueerdo and others with better understanding on this to post a more generic approach so that it can help others because I think many people who can't find a right approach in such conditions, end up using LIKE in place of = but that completely changes the core idea of the query.

Related

searching datas in the database with prepare statement

a quick question :), I wrote this because someone said that my codes are vulnerable to mysql injection and it is a requirement to learn prepared statement in web programming to avoid any user putting malicious data or statement into the database..What I have is a search function that search data from the database, if you type in a string like this "torres" then i search for torres but if you just put "tor" it won't search for datas that contain "tor" in their name..I don't know the correct format while using prepared statement, If you have advice I'm very happy to take it :)
<?php
if (isset($_POST['search'])) {
$box = $_POST['box'];
$box = preg_replace("#[^0-9a-z]#i","",$box);
$grade =$_POST['grade'];
$section = $_POST['section'];
$strand = $_POST['strand'];
$sql = "SELECT * FROM student WHERE fname LIKE ? or lname LIKE ? or mname LIKE ? or grade = ? or track = ? or section = ?";
$stmt = mysqli_stmt_init($conn);
if (!mysqli_stmt_prepare($stmt, $sql)){
echo "SQL FAILED";
}
else {
//bind the parameter place holder
mysqli_stmt_bind_param($stmt, "ssssss",$box, $box, $box, $grade, $strand, $section);
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);
while($row = mysqli_fetch_assoc($result))
{
echo "<tr>";
echo "<td>".$row['lname']."</td>";
echo "<td>".$row['fname']."</td>";
echo "<td>".$row['mname']."</td>";
echo "<td>".$row['grade']."</td>";
echo "<td>".$row['track']."</td>";
echo "<td>".$row['section']."</td>";
echo "</tr>";
}
}
As requested:
#ArtisticPhoenix I clearly prefer the king's way [compound full text index]. This should be your primary answer showing an example/explaination.
First make a full text index that includes all three fields (this is in PHPmyAdmin, it's a bit easier to explain with an image)
Then do a query like this:
#PDO version SELECT * FROM `temp` WHERE MATCH(fname,mname,lname)AGAINST(:fullname IN BOOLEAN MODE)
#MySqli version SELECT * FROM `temp` WHERE MATCH(fname,mname,lname)AGAINST(? IN BOOLEAN MODE)
SELECT * FROM `temp` WHERE MATCH(fname,mname,lname)AGAINST('edward' IN BOOLEAN MODE)
It seems simple but there are some things with full text to be aware of Min char count which is 3 (I think) anything smaller than that is not searched on. This can be changed but it requires repairing the DB and restarting MySql.
Stop words, these are things like and, the etc. These can also be configured in my.cnf.
Punctuation is ignored. This might not seem a big deal on names but think of hyphenated last names.
Usually I reduce the word min to 2 and point the stopwords to an empty file (disabling them).
The match against syntax is quite different, it's pretty powerful but it's not really used outside of full text. An example is: this is the wild card * and you use '"' double quotes for exact phrase match '"match exactly"', and + is logical AND, such as word+ word+ (default is or), - is do not match this etc... If I remember right, I used it a bunch a few years ago but haven't had to use it recently.
For example doing "begins with" on a partial word
SELECT * FROM `temp` WHERE MATCH(fname,mname,lname)AGAINST('edwar*' IN BOOLEAN MODE)
Same result matches one row. The obvious benefit is searching all 3 fields at the same time, but the full text syntax itself can be quite useful too.
For more information:
https://dev.mysql.com/doc/refman/8.0/en/fulltext-boolean.html
PS. I might add that using OR in a query can really kill performance, I've went as far as to replace simple OR with a UNION because of how bad the performance is on a large table. Logically the DB optimizer has to rescan the entire table for an OR, unlike AND where it can use the result of the previous expression to reduce the next expressions data set (or that is how I understand it). I can say the performance difference is very noticeable using OR vs UNION.
This is true for a compound full text index vs doing OR on each field separately. By default fulltext is faster, but it's even faster this way.
To fix your current query (for the sake of completeness)
You need whats known as an exclusive or, like this:
SELECT * FROM student WHERE ( fname LIKE ? OR lname LIKE ? OR mname LIKE ? ) AND grade = ? AND track = ? AND section = ?
What this does is group the OR's together so that they evalute as one expression to the "next level up" ( outside the parenthesis ). Basically order of operations. In English, you would have to match at least 1 of these columns fname, lname, mname AND you would also have to match all of the rest of the columns as well, to get a result returned for any given row.
If you use all OR (as you are now) and any single field matches, then the query comes back as true with matches. Which is the behaviour you are experiencing now.
If you simply change everything outside of the name fields to AND, Basically remove the parenthesis
Like this:
#this is wrong don't use it.
SELECT * FROM student WHERE fname LIKE ? OR lname LIKE ? OR mname LIKE ? AND grade = ? AND track = ? AND section = ?
Then you have to match this way.
(grade AND track AND section AND mname) OR lname OR fname
So if the last or first name match you get results regardless of any of the other fields. But the mname field you would find has to match with all the rest of the fields to get a result (but you would not likely notice this). Because, it would seem that the query works how you want but only when the mname is a match.
I hope that makes sense. It may be helpful to think of the WHERE clause as an IF condition the same logic rules apply.
Cheers!

mySQL: How do I combine a search value with a variable?

I'm sure that there is a stupidly simple solution to this, but unfortunately my google-fu is too weak to find it.
I have a number of different tables for sizing, all following the same naming convention i.e size_001, size_002 etc. Within a loop I need to get the size entry that matches with the results already found.
Unfortunately there are no totally unique identifiers, as they repeat in each table (roman numerals for sizing). But they are unique in each individual table. So what I've tried so far looks a little bit like this:
SELECT * FROM CONCAT('size_00', '.$sizeTableID[$j].') WHERE sizeName LIKE '$sizeNames[$j]'"
Where $sizeTableId is a number from 1-9 and sizeName is a string e.g II or VI or, occasionally (because there's no consisitency), 2 etc
I've also tried ''$var'' inside the CONCAT and not using the CONCAT at all. Really I just need a way to join the database.size_00 and an integer variable.
If I understand correctly, this is actually simple:
$tablename = 'size00'.$sizeTableID[$j];
$sql = "SELECT * FROM $tablename WHERE sizeName LIKE '{$sizeNames[$j]}'";
and I think that solves it.
PHP is a bit quirky here.....
Try this one (when the variable is from an array/object, surround it with {})
$sql = "SELECT * FROM CONCAT('size_00', '{$sizeTableID[$j]}') WHERE sizeName LIKE '{$sizeNames[$j]}'";

Why is this string operator not registering valid match with fetch_assoc()?

As the code is, I think the associative value of 'aurapass' is picking up as a string rather than the corresponding fetch value. Everything is returning positive. How do I select the fetch_assoc() value?
$recruiter=$_POST["recruiter"];
$aurapass=$_POST["aurapass"];
$recruitfetch=mysqli_query($maindb, "SELECT * FROM auras WHERE auraname = $recruiter");
$recruitcheck=mysqli_fetch_assoc($recruitfetch);
if($recruitcheck['aurapass']==$aurapass){
if($recruitcheck['recruitbadge']=="valid"){
echo "<script>alert('Recruiter badge verified.')</script>";
}
}
I have since changed the variables to be different words, so I can test the true value of the variables, and the column names, and string value of "valid" matches the table database values, so what I the problem, here?
With changes, the current code reads:
$recruiter=$_POST["recruiter"];
$recruitpass=$_POST["recruitpass"];
$recruitfetch=mysqli_query($maindb, "SELECT * FROM auras WHERE auraname = '$recruiter'");
$recruitcheck=mysqli_fetch_assoc($recruitfetch);
if($recruitcheck['aurapass']==$recruitpass){
if($recruitcheck['recruitbadge']=="valid"){
echo "<script>alert('Recruiter badge verified.')</script>";
}
}
I am struggling to receive any sort of printout, or echo, to show the values of anything. I am extremely new to this, and struggling. Unfortunately, I have not found sites that talk about exact syntax, especially with PHP7.0. Any advice on troubleshooting this would be fantastic!
Adding the quotes to recruiter did change the results, so apparently the code is correct in the second version, but I think I had some sort of character errors because I had to retype it to get it to work, but it is still the same exact text?
This is what I ended with:
$recruiter=$_POST["recruiter"];
$recruitpass=$_POST["recruitpass"];
$recruitfetch=mysqli_query($maindb, "SELECT * FROM auras WHERE auraname = '$recruiter'");
$recruitcheck=mysqli_fetch_assoc($recruitfetch);
if($recruitcheck["aurapass"]==$recruitpass){
if($recruitcheck["recruitbadge"]=="valid"){
I also figured out how to print a var_dump, and I understand its use. Thank you, all!

Running a MySQL query using a string in php

Answer found (syntax): The column name of my string had to be encased in backticks " ` " as they contained spaces. Note that this means that the majority of this post has no relevance to the issue. The code has been corrected in case someone wants to do something similar.
So, I am doing a foreach loop to assign a value (1/0) to non-static columns in my database (it needs to support addition/deletion/editing of columns). I am using $connectionvar->query($queryvar); to do my queries which worked fine up until now when I'm trying to use a custom built string as $queryvar in order to change the column name to a variable within the loop. I've been outputting this string through echo and it looks exactly like my functional queries but somehow doesn't run. I've attempted to use eval() to solve this but to no avail (I feel safe using eval() as the user input is radio buttons).
Here's the loop as well as my thought processes behind the code. If something seems incoherent or just plain stupid, refer to my username.
foreach($rdb as $x) { //$rdb is a variable retrieved from $_POST earlier in the code.
$pieces = explode("qqqppp", $x); //Splits the string in two (column name and value) (this is a workaround to radio buttons only sending 1 value)
$qualname = $pieces[0]; //Column name from exploded string
$qualbool = $pieces[1]; //desired row value from exploded string
$sql = 'UPDATE users SET '; //building the query string
$sql .= '`$qualname`';
$sql .= '=\'$qualbool\' WHERE username=\'$profilename\''; //$profilename is retrieved earlier to keep track of the profile I am editing.
eval("\$sql = \"$sql\";"); //This fills out the variables in the above string.
$conn->query($sql); //Runs the query (works)
echo ' '.$sql.' <br>'; //echoes the query strings on my page, they have the exact same output format as my regular queries have.
}
}}
Here's an example of what the echo of the string looks like:
UPDATE users SET Example Qualification 3='1' WHERE username='Admin2'
For comparison, echoing a similar (working) query variable outside of this loop (for static columns) looks like this:
UPDATE users SET profiletext='qqq' WHERE username='Admin2'
As you can see the string format is definitely as planned, yet somehow doesn't execute. What am I doing wrong?
PS. Yes I did research this to death before posting it, as I have hundreds of other issues since I started web developing a month ago. Somehow this one has left me stumped though, perhaps due to it being a god awful hack that nobody would even consider in the first place.
You need to use backticks when referring to column names which have spaces in them. So your first query from the loop is outputting as this:
UPDATE users SET Example Qualification 3='1' WHERE username='Admin2'
But it should be this:
UPDATE users SET `Example Qualification 3`='1' WHERE username='Admin2'
Change your PHP code to this:
$sql = 'UPDATE users SET `'; // I added an opening backtick around the column name
$sql .= '$qualname`'; // I added a closing backtick around the column name
$sql .= '=\'$qualbool\' WHERE username=\'$profilename\'';
Example Qualification 3 : Is that the name of your Mysql Column name ?
You shouldnt use spaces nor upper / lower case in your columnname.
Prefere : example_qualification_3
EDIT :
To get column name and Comment
SHOW FULL COLUMNS FROM users

MySQL SELECT statement using PHP GET variable

I have a PHP script that is generating a MySQL select statement:
select * from words where word = 'Classic'
There is exactly one word in the words table with the variable word equal to Classic.
When my PHP page executes, I get no results from the query. If I echo the string that is being used to execute the query, cut and paste that into the SQL window in PHPMyAdmin in the database, I also get no results. However, if I re-type that EXACT string into the SQL window in PHPMyAdmin (with the same quote characters), I get the proper result of one row.
The word Classic from the select statement is gotten from a PHP GET (see code below). I can echo the $word variable, and get the correct result of 'Classic'. What am I doing wrong?
Here is my code:
<?php
require ('dbconnect.php');
$word = $_GET["word"];
$selectStr = "SELECT * FROM words WHERE word = '" . $word . "'";
if ($results = MySQL($dbName, $selectStr))
{
$rowCount = MySQL_NUMROWS($results);
}
$resultRow = MYSQL_FETCH_ROW($results);
$wordID = $resultRow[0];
?>
Please, please, please sanitize that word. mysql_real_escape_string() should do the trick.
$selectStr = "SELECT * FROM words WHERE word LIKE '" . $sanitized_word_i_promise . "'"; should work :)
Just to explain: "=" should work for exact matches. This includes uppercase / lowercase, spaces etc. You should probably trim that result first too, before using it in the query.
If you have foo stored in the database (note the space at the end) - it won't match foo, without a space. You'll want to use LIKE 'foo%' - probably.
Either way, Sourabh is right, although performance wise, this isn't a big hit when trying to match exact strings, you should look for the problem in other places first (such as, is the item in the database an exact match?).
First off you should not take any user input and directly input it into a query without sanitizing it, or using a prepared statement.
Now that we've gotten that out of the way: have you tried doing a strcmp() with the variable and your string written in? Such as
echo strcmp($_GET['word'], "Classic")
If you get a result other than 0 it means they are not the same, most likely there will be a whitespace of some sort in the $_GET variable. use trim() on it to take out whitespace. Also could be a case sensitivity issue as well.

Categories