search for multiple words using mysql MATCH AGAINST - php

I am using this basic mySQL query which works great:
$sql = "SELECT * FROM `clients` WHERE
MATCH(`LNAME`) AGAINST('$c') OR
MATCH(`FNAME`) AGAINST('$c') OR
MATCH(`MAIL`) AGAINST('$c') OR
MATCH(`TEL`) AGAINST('$c') "
where $c is the search query. Now this works with all single words/numbers but whenever I add 2 words no results are returned.
For example, if my database has aaaa bbbb in LNAME and I search for "aaaa bbbb" I get nothing back, however when I search for "aaaa" or "bbbb" it does work. I tried adding IN BOOLEAN MODE but it doesn't make a difference.
Could ayone explain to me how this works? $c is composed of letters, numbers and/or a #
thanks a lot.

First , you should use MATCH AGAINST like this:
$sql = "SELECT * FROM `clients` WHERE MATCH(`LNAME`,`FNAME`,`MAIL`,`TEL`) AGAINST('$c')"
Please notice:
Short words are ignored, the default minimum length is 4 characters.
You can change the min and max word length with the variables
ft_min_word_len and ft_max_word_len
and:
If a word is present in more than 50% of the rows it will have a
weight of zero. This has advantages on large datasets, but can make
testing difficult on small ones.
You can use LIKE and it probably will have better results.
Example of usage:
$sql = "SELECT * FROM `clients` WHERE `LNAME` LIKE '%$c%' OR `FNAME` LIKE '%$c%' OR ..."

Related

Get all values from SQL that contains certain value

I'm trying to get all values from table products, that contains for example shirt.
In this case $thin is getting values from searach box "stxt".
It means that if $thin = shirt, I want to get shirt, t-shirt etc. Right now, only thing that I get is only shirt, despite if I will use "LIKE" or "=" as operator in $sql statement.
$thin = $_POST['stxt'];
$thing = strtoupper($thin);
$sql = "select * from products where upper(productName) LIKE '$thing'";
In your query, put in your LIKE % before and after your variable.
Like this "%$variable%".
If you want there to be just a number of n characters before or after your variable, put the _ symbol n times.
And for security reasons, try to use prepared statements.
Link sql like: https://sql.sh/cours/where/like
can you use a regexp operator ?
$sql = "select * from products where productName regexp $thing";
$thin = $_POST['stxt'];
$thing = strtoupper($thin);
$sql = "select * from products where upper(productName) LIKE '%$thing%'";
MSSQL needs % wildcards, other SQL dialects may differ.
Alternatively you could do a REPLACE(productName,'$thing','') and compare the length of that to the original length.
Either way it is going to be a full table scan unless you have full text indexes set up.

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]}'";

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

MySQL select from char column using int - leading zero causes unexpected result

I have the following data:
stockcode (CHAR) | description (VARCHAR)
----------------------------------------------
1234 | some product
01234 | some other product
I run the following code:
$sql = "SELECT * FROM stock WHERE stockcode = " . $db->quoteSmart($stockcode)
$res = $db->query($sql);
If I pass the stock code "01234" in, I get the second row as expected. If I pass in "1234" I get both rows, when I expect to only get the first.
By echoing out the sql statements, it seems to be because only the 01234 stockcode gets quotes around it, the 1234 one doesn't (presumably quoteSmart thinks as it is an integer it doesn't need quoting?).
Mysql is then comparing the int 1234 to the CHAR column, and deciding they both match (presumably it is doing the comparison as ints?)
There are a lot of places in the code which build queries like this, and 99% of the time, the stockcode variable will be alphanumeric, it's only occasionaly entirely numeric, and very rarely contains a leading zero, this is just a fluke occurrence I stumbled across today.
Can anyone recomend an easy solution?
Try explicitly casting your variables to strings:
$db->quoteSmart((string)$stockcode);
// instead of:
// $db->quoteSmart($stockcode);
Edit:
If this does not work, I imagine that quoteSmart() isn't really that smart (or it's trying to be too smart for it's own good), so you'll very likely need to stop using it and stick to bound parameters (which I suggest over this method anyway).
Add quotes so the char in the database don't get converted to numbers for the comparison
$sql = "SELECT * FROM stock
WHERE stockcode = '" . $db->quoteSmart($stockcode). "'"
2nd Version:
$stockcode_str = $db->quoteSmart($stockcode);
if (is_numeric($stockcode_str))
$stockcode_str = "'$stockcode_str'";
$sql = "SELECT * FROM stock
WHERE stockcode = $stockcode_str";

Converting varchar into an int just for the search query?

What I've been trying to do is to select a row from a table while treating the varchar cells as int ones,
Here's a little explanation:
I have a table of phone numbers, some have "-" in them, some don't.
I wanted to select a number from the database, without including those "-" in the query.
So I used this preg_replace function:
$number = preg_replace("/[^0-9]/","",$number); //that leaves only the numbers in the variable
and then I run the following query:
"SELECT * FROM `contacts` WHERE `phone` = '{$number}'"
Now, of course it won't match sometimes since the number Im searching may have "-" in the database, so I tried to look for a solution,
on solution is just converting the cells into int's, but I'm not interested in doing that,
So after looking around, I found a MySQL function named CAST, used like : CAST(phone AS UNSIGNED)
I tried to mess with it, but it didn't seem to work.
Edit:
I kept looking around for a solution, and eventually used MySQL's REPLACE function for that.
"SELECT * FROM `contacts` WHERE REPLACE(phone,'-','') = '{$number}'"
Thank you all for your help.
MySQL doesn’t support extraction of regex matches.
You could try writing a stored function to handle it, but your best bet is to convert the data to ints so that all the numbers are uniform. I know you said you don't want to do that, but if you can, then it’s the best thing to do. Otherwise, you could do something like:
"SELECT * FROM `contacts` WHERE `phone` = '{$number}' OR `phone` = '{$number_with_dashes}'"
That is, search for the plain number OR the number with dashes.
1.
The easiest way to do it might be by using the REPLACE operator.
SELECT * FROM `contacts` WHERE REPLACE(REPLACE(`phone`, '-', ''), ' ', '') = '5550100';
What it does is simpy replacing all whitespaces and dashes with nothing, namely removing all spaces and dashes.
2.
Another alternative to solve the problem would be to use LIKE. If the phone numbers with a dash always are formatted the same way like 555-0100 and 555-0199 you can simple insert a %-sign instead of the dash. If your number may be formatted in different ways you can insert a %-between every character. It's not a beautiful solution but it does the trick.
SELECT * FROM `contacts` WHERE `phone` LIKE '555%0100';
or
SELECT * FROM `contacts` WHERE `phone` LIKE '5%5%5%0%1%0%0';
3.
You can use regular expressions. Since MySQL doesn't implement regex replace functions you need to use user defined functions. Have a look at https://launchpad.net/mysql-udf-regexp. It supports REGEXP_LIKE, REGEXP_SUBSTR, REGEXP_INSTR and REGEXP_REPLACE.
Edit: Removed my first answer and added some other alternatives.
I kept looking around for a solution, and eventually used MySQL's REPLACE function for that.
"SELECT * FROM `contacts` WHERE REPLACE(phone,'-','') = '{$number}'"

Categories