MYSQL ORDER BY with an array of values in WHERE clause - mysql

I am working on a part of a search script where the submitted search string is parsed and each significant term placed into an array. The array is then looped through in the WHERE clause to search several columns in the MYSQL database. Here's a sample SQL code:
$sql = "SELECT title, question, tag1, tag2, tag3, tag4, tag5 FROM question WHERE ";
while(list($key,$val)=each($split_stemmed)){
if($val<>" " and strlen($val) > 0){
$sql .=
"(title LIKE '$val%'
OR question LIKE '$val%'
OR tag1 LIKE '$val%'
OR tag2 LIKE '$val%'
OR tag3 LIKE '$val%'
OR tag4 LIKE '$val%'
OR tag5 LIKE '$val%') OR";
}
}
$sql=substr($sql,0,(strLen($sql)-3));
$sql .= "GROUP BY q_id ORDER BY
((title LIKE '$val%') +
(question LIKE '$val%') +
(tag1 LIKE '$val%') +
(tag2 LIKE '$val') +
(tag3 LIKE '$val%') +
(tag4 LIKE '$val%') +
(tag5 LIKE '$val%')) desc, title asc";
The problem I am having is getting the ORDER BY to work correctly. The ORDER BY's purpose is to arrange the results of the query from the order of most hits on the search string to the least. My assumption is that I somehow need to loop through the array again in the ORDER BY clause, but am not sure of how to do this or if I am even correct in that assumption. Any helpers out there?
I know I can probably do this simpler using mysql full text search but the tables being used are InnoDB, so I dont think that is an option as of yet.

A couple of issues to consider...
1) a NULL value in any of the columns tag1, tag2, tag3... in the ORDER BY expression is going to return a NULL for the entire expression. Consider:
SELECT 0 + NULL + 1 + 0
If all of those columns are defined as NOT NULL, then this isn't an issue. But more generally, you'd want to insulate from NULL values...
ORDER BY ( IFNULL(title LIKE '$val%'),0) +
IFNULL(question LIKE '$val%'),0) +
IFNULL(tag1 LIKE '$val%'),0) +
IFNULL(tag2 LIKE '$val' ),0) +
-or alternatively-
ORDER BY ( IFNULL(title ,'') LIKE '$val%') +
IFNULL(question,'') LIKE '$val%') +
IFNULL(tag1 ,'') LIKE '$val%') +
IFNULL(tag2 ,'') LIKE '$val' ) +
)
(Seems like you're missing a % on tag2 based on the pattern, but it's entirely possible that omission is intentional
2) It's not at all clear why you need a GROUP BY q_id in your query.
I'd recommend you test by taking the expression in the ORDER BY clause, and copy it to your SELECT list, and run the query to see the values that it's returning.
In MySQL, if you add that expression to the SELECT list and give it an alias, you can reference the alias on the ORDER BY.
SELECT expr AS match_count, ...
FROM
ORDER BY match_count DESC

The functionality you're looking for -- searching multiple columns for search terms and ordering by relevance -- is exactly what full-text search was designed for. If at all possible, you should use this as it will reduce your headaches in the long run.
If you absolutely must implement this way, then it's necessary to move the LIKE statements into the SELECT clause so that you can sum them. Like this:
SUM (CASE WHEN title LIKE '$val%' THEN 1 ELSE 0 END
+ CASE WHEN question LIKE '$val%' THEN 1 ELSE 0 END
+ CASE WHEN tag1 LIKE '$val%' THEN 1 ELSE 0 END
... etc
) AS relevance
Then to select only the matches, you could use HAVING relevance > 0. And to order, you would simply use ORDER BY relevance DESC (since the relevance column as above will give you a count of the number of matching columns).

Related

MySQL ORDER BY CASE + operator

I am trying to do a search that would be sorted by relevance.
Let's say the search term contains 3 words: A, B and C. What I am trying to do is to check if the search term is present in the SELECT result and if yes that would increase its rank.
ORDER BY CASE
(
WHEN search_word_A_is_present THEN +1
WHEN search_word_B_is_present THEN +1
WHEN search_word_C_is_present THEN +1
ELSE 0
END
)
DESC
While there is no syntax error and the search runs and sorts by something (that seems different from what I want) but I am not sure what is being added up if anything. How would I go about seeing what the final rank (sum) is at the end for each result? Is this the correct way to do it?
Since in MySQL boolean conditions result in 1 and 0, you can simply add those up
ORDER BY search_word_A_is_present + search_word_B_is_present + search_word_C_is_present
DESC
A more practical example:
ORDER BY col1 = 1 + col2 = 'A' + col3 = 44 DESC

Matching key words in mysql database

m trying to match key word but not exactly, something relevant, i use sql LIKE with wilcard %% something like '%mens, shoe%', will match every data with either men, mens shoe or even both, but the problem is if a user uses an apostrophe sign like this '%men\'s, shoe%', this will only match record having men's shoe or having men's with apostrophe and will not match men or mens is there a way i can make input with apostrophe sign match records without apostrophe sign thanks for any help
I'm editing my question and adding the SQL statement how it looks like
SELECT SQL_CALC_FOUND_ROWS p.product_id,p.title,p.price,p.unit_sold,p.slug,p.discount,p.free_shipping,free_return,
p.profile_img,p.store_name,p.item_number,
(
(-- Title score
if (title LIKE '%men\'s, shoe%',6,0) + if (title LIKE '%men\'s%',5,0) + if (title LIKE '%shoe%',5,0)
)+
(-- description
if (description LIKE '%men\'s, shoe%',5,0) + if (description LIKE '%men\'s%',4,0) + if (description LIKE '%shoe%',4,0)
)+
(-- item number
if (item_number = 'men\'s, shoe',4,0) + if (item_number = 'men\'s',3,0) + if (item_number = 'shoe',3,0)
)+
(-- category id
if (category_id = 'men\'s, shoe',4,0) + if (category_id = 'men\'s',3,0) + if (category_id = 'shoe',3,0)
)
) as relevance
FROM products p
WHERE p.is_active = '1'
HAVING relevance > 0
ORDER BY relevance DESC LIMIT 2,2
Your condition should look like:
someColumn LIKE '%men''s%' or someColumn LIKE '%men\''s%' or someColumn LIKE '%shoe%'
where someColumn is column name you are interested in. It will match any occurences like: men's, men\'s, etc.
Remove apostrophes before comparing:
(-- Title score
(case when replace(title, '''', '') LIKE '%mens, shoe%' then 16
when replace(title, '''', '') LIKE '%men%' then 5
when replace(title, '''', '') LIKE '%shoe%' then 5
else 0
end) +
. . .
That said, you might want to look into full text search. It might be a simpler way to accomplish what you want.

SQL How to sort by "Ranges"

I am currently using a database with different entries like dates, names, but also one column with time "ranges". This basically means that there can be a definite number like "10" in this cell, but also a value like "10-15" or "5-10".
So what I want to do here is to sort them by an "average" value ((Lowest+Highest)/2). So in case of the 3 mentioned values it should be
5-10
10
10-15
I am wondering if it is possible to embed this into the SQL statement in some way.
And if it is not possible, I'd like to know the easiest way to implement it otherwise.
Right now I am putting the $SQL_statement together via several conditions, then putting everything into $resultset which is then used with "while". Here are some snippets:
$resultset=mysql_query($SQL_statement);
while ($currententry=mysql_fetch_array($resultset))
{
echo $currententry['Platform'];
echo $currententry['PlaytimeInH']."h";
}
You can do this with substring_index() and arithmetic:
order by (substring_index(col, '-', 1) + 0 +
substring_index(col, '-', -1) + 0
) / 2
The division by 2 is unnecessary, but you do specify the average in your question.
Note that the above will work even if col has no hyphen in it.
You could use a select with a case when clause in order by
select col1, col2, cole
from your_table
order by case
when your_column = '5-10' then 1
when your_column = '10-15' then 2
when your_column = '15-20' then 3
else 4
end

In MySQL, how to get all strings containing at least two characters in predefined list

I have a table of strings and want to retrieve all rows which contain at least two characters of a predefined list. Better explained by example:
My table looks like this:
Id|Word
1|Cat
2|Chicken
3|Dog
4|Elephant
5|Fish
6|Goat
This could be my char list:
Characterlist = 'A', 'B', 'C', 'E'
The select statement should then return:
Cat, Chicken, Elephant
I have looked through the string functions in mySQL docs but can not find a suitable function for doing this. Is it even possible?
Here's an inefficient way which relies on adding up the 0 or 1s returned by boolean conditions:
SELECT
*,
(
(UPPER(Word) LIKE '%A%') +
(UPPER(Word) LIKE '%B%') +
(UPPER(Word) LIKE '%C%') +
(UPPER(Word) LIKE '%D%')
) AS lettermatches
FROM yourtable
HAVING lettermatches >= 2
The LIKE conditions each return a 0 or 1. Those are added together, and the HAVING clause limits the result to the rows scoring 2 or greater.
It might be faster to use LOCATE() instead of LIKE:
SELECT
*,
(
(LOCATE('A', UPPER(Word)) > 0) +
(LOCATE('B', UPPER(Word)) > 0) +
(LOCATE('C', UPPER(Word)) > 0) +
(LOCATE('D', UPPER(Word)) > 0)
) AS lettermatches
FROM yourtable
HAVING lettermatches >= 2

A "Search" mysql query issue

I have this query where I can search the TABLE_GLOBAL_PRODUCTS
$catglobal_sql = "
select p.*,
case when
p.specials_new_products_price >= 0.0000
and p.expires_date > Now()
and p.status != 0
then p.specials_new_products_price
else p.products_price
end price
from ".TABLE_GLOBAL_PRODUCTS." p
INNER JOIN ".TABLE_STORES." s ON s.blog_id = p.blog_id
where
MATCH (p.products_name,p.products_description) AGAINST ('%".$search_key."%')
OR p.products_name like '%".$search_key."%'
order by p.products_date_added DESC, p.products_name";
The issue here is that, when I search with phrases like Cotton Shirts it displays correct results. However, when I only input a single word like Cotton it displays no results instead of displaying the same as when you input a phrase like Cotton Shirts.
Use * instead of % as a wildcard when using MATCH ... AGAINST ...
So the match part of your code should look like:
...
MATCH (p.products_name,p.products_description) AGAINST ('*".$search_key."*')
...
In MATCH the wildcards are slightly different
To match zero or more characters use
In MATCH '*'
In LIKE '%'
To match any single character use
In MATCH '?'
In LIKE '_'