Matching key words in mysql database - mysql

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.

Related

Is there a way to count the LIKE results per row in MySQL?

I have a MySQL table jobs like this:
ID | title | keywords
1 | UI Designer | HTML, CSS, Photoshop
2 | Web site Designer | PHP
3 | UI/UX Developer | CSS, HTML, JavaScript
and I have a query like this:
SELECT * FROM jobs
WHERE title LIKE '%UX%' OR title LIKE '%UI%' OR title LIKE '%Developer%' OR keywords LIKE '%HTML%' OR keywords LIKE '%CSS%'
I want to sort results by most similarity.
for example for first row (ID 1), there is UI and HTML and CSS in the record row. then the number of CORRECT LIKE conditions is 3 for first row. same as this calculation, it is 0 for second row and it is 5 for third row.
then I want the result ordered by the number of CORRECT LIKE conditions, like this:
Results
ID | title | keywords
3 | UI/UX Developer | CSS, HTML, JavaScript
1 | UI Designer | HTML, CSS, Photoshop
Then, is there anyway to count the number of similarities per row in query and sort the result like what I describe?
You could sum the matching resul in order by using if
SELECT *
FROM jobs
WHERE title LIKE '%UX%'
OR title LIKE '%UI%'
OR title LIKE '%Developer%'
OR keywords LIKE '%HTML%'
OR keywords LIKE '%CSS%'
ORDER BY (title LIKE '%UX%'+ title LIKE '%UI%'+
keywords LIKE '%HTML%'+ keywords LIKE '%HTML%') DESC
if return 1 or 0 so adding the true result you should obatin the most matching rows
You should not be storing keywords in a string like that. You should have a separate table.
If -- for some reason such as someone else's really, really, really bad design choices -- you have to deal with this data, then take the delimiters into account. In MySQL, I would recommend find_in_set() for this purpose:
SELECT j.*
FROM jobs j
WHERE title LIKE '%UX%' OR
title LIKE '%UI%' OR
title LIKE '%Developer%' OR
FIND_IN_SET('HTML', REPLACE(keywords, ', ', '')) > 0 OR
FIND_IN_SET('CSS', REPLACE(keywords, ', ', '')) > 0
ORDER BY ( (title LIKE '%UX%') +
(title LIKE '%UI%') +
(title LIKE '%Developer%') +
(FIND_IN_SET('HTML', REPLACE(keywords, ', ', '')) > 0) +
(FIND_IN_SET('CSS', REPLACE(keywords, ', ', '')) > 0)
) DESC ;
This finds an exact match on the keyword.
You can simplify the WHERE, but not the ORDER BY, to:
WHERE title REGEXP 'UX|UI|Developer' OR
FIND_IN_SET('HTML', REPLACE(keywords, ', ', '')) > 0 OR
FIND_IN_SET('CSS', REPLACE(keywords, ', ', '')) > 0

Search row with specific value

Here's the table
*City Crime*
Bangkok High
Hongkong Very High
Seoul Low, Average
Texas Average, High
Jakarta Low
Singapore Very Low
Las Vegas Average, Low
how's the sql to search where the crime "Low"
i use the preg_split but i don't know to match the database
Use the LIKE matcher to select for a partial match on a string:
SELECT *
FROM cities
WHERE crime LIKE '%Low%'
If you need case insensitivity, use LOWER(crime) to convert the column to lowercase.
Try it.
Mysql:
SELECT *
FROM City
WHERE `Crime` REGEXP '^Low' or `Crime` REGEXP ', Low'
or `Crime` REGEXP 'Low,'
Sql:
select * from City
where (Crime like 'low%' or Crime like '%, low%' or Crime like '%low,%')
select *
from table
where
`crime` like '%Low%'
and `crime` not like '%Very Low%';
You select records where some criteria is met with WHERE.
select * from mytable where crime = 'Low';
There are further entries in your table where the crime string contains a 'Low' substring. E.g. 'Low, Average' and 'Average, Low'. I don't know the exact meaning of these, of course. Do both mean the same? Do they mean the crime is "low to avarage"? Or is it undecided whether "low or avarage"? And would you count this as "low" or would that be yet another level above "low"?
Then there is the entry 'Very Low'. Would you consider this "low" or a level beyond?
Depending on the answers you could extend above query to match all 'Low' substrings:
select * from mytable where crime like '%Low%';
Or use some more advanced string search, e.g.
select * from mytable
where ',' || replace(replace(crime, ', ', ','), ' ,', ',') || ',' like '%,Low,%';
which would get 'Low, Average' and 'Average, Low', but not 'Very Low'.

finding a number in space separated list with REGEXP

I am writing a SQL query to select row, where a field with space separated numbers contains a single number, in this example the 1.
Example fields:
"1 2 3 4 5 11 12 21" - match, contains number one
"2 3 4 6 11 101" - no match, does not contain number one
The best query so far is:
$sql = "SELECT * from " . $table . " WHERE brands REGEXP '[/^1$/]' ORDER BY name ASC;";
Problem is that this REGEXP also finds 11 a match
I read many suggestions on other post, for instance [\d]{1}, but the result always is the same.
Is it possible to accomplish what I want, and how?
You don't need regex: You can use LIKE if you add a space to the front and back of the column:
SELECT * from $table
WHERE CONCAT(' ', brands, ' ') LIKE '% 1 %'
ORDER BY name
Try:
WHERE brands REGEXP '[[:<:]]1[[:>:]]'
[[:<:]] and [[:>:]] match word boundaries before and after a word.
Why not FIND_IN_SET() + REPLACE() ?
SELECT
*
FROM
`table`
WHERE
FIND_IN_SET(1, REPLACE(`brands`, ' ', ','))
ORDER BY
`name` ASC;

MYSQL ORDER BY with an array of values in WHERE clause

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).

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 '_'