Why is dot metacharactor of regex not working in mysql? - mysql

I have two records with names bowser and Tommy in the table pet. Now when I run the following query in cmd nothing happen:
SELECT * FROM pet WHERE name LIKE '.%';
On the other hand the following query matches Bowser record:
SELECT * FROM pet WHERE name LIKE 'b%';
As far as I know, . should match any character. So '.%' should match every word.
Why is dot metacharactor of regex not working in mysql?

The reason your query doesn't work is because it is looking for names that start with a period. That is how LIKE works.
Use RLIKE or REGEXP:
WHERE name REGEXP '.*';
LIKE uses the ANSI standard for the operator. The equivalent of . is _. However, the way LIKE works is different from regular expressions.
The documentation does a good job of explaining the differences between LIKE and REGEXP.

Related

Why isn't MySQL REGEXP filtering out these values?

So I'm trying to find what "special characters" have been used in my customer names. I'm going through updating this query to find them all one-by-one, but it's still showing all customers with a - despite me trying to exlude that in the query.
Here's the query I'm using:
SELECT * FROM customer WHERE name REGEXP "[^\da-zA-Z\ \.\&\-\(\)\,]+";
This customer (and many others with a dash) are still showing in the query results:
Test-able Software Ltd
What am I missing? Based on that regexp, shouldn't that one be excluded from the query results?
Testing it on https://regex101.com/r/AMOwaj/1 shows there is no match.
Edit - So I want to FIND any which have characters other than the ones in the regex character set. Not exclude any which do have these characters.
Your code checks if the string contains any character that does not belong to the character class, while you want to ensure that none does belong to it.
You can use ^ and $ to check the while string at once:
SELECT * FROM customer WHERE name REGEXP '^[^\da-zA-Z .&\-(),]+$';
This would probably be simpler expressed with NOT, and without negating the character class:
SELECT * FROM customer WHERE name NOT REGEXP '[\da-zA-Z .&\-(),]';
Note that you don't need to escape all the characters within the character class, except probably for -.
Use [0-9] or [[:digit:]] to match digits irrespective of MySQL version.
Use the hyphen where it can't make part of a range construction.
Fix the expression as
SELECT * FROM customer WHERE name REGEXP "[^0-9a-zA-Z .&(),-]+";
If the entire text should match this pattern, enclose with ^ / $:
SELECT * FROM customer WHERE name REGEXP "^[^0-9a-zA-Z .&(),-]+$";
- implies a range except if it is first. (Well, after the "not" (^).)
So use
"[^-0-9a-zA-Z .&(),]"
I removed the + at the end because you don't really care how many; this way it will stop after finding one.

What is the best way to use MYSQL Search on term not working

What is the best way to search a database for a phrase such as "Almond Anise Cookie" and return the result?
If I
SELECT *
FROM recipes
WHERE name LIKE '%".$query."%'
and use the phrase "Almond Cookie", nothing is returned as expected. But if I search for "Anise Cookie" the result above is returned.
I've also tried
SELECT *
FROM recipes
WHERE name LIKE '%".$query."%'
OR name LIKE '".$query."%'
OR name LIKE '%".$query."'
with the same failed result.
Using MATCH AGAINST returns everything that contains "Almond" and everything that contains "Cookie" also not a good result. Is there a happy middle in returned results?
You can try using REPLACE. Something like this should work:
SELECT *
FROM recipes
WHERE NAME LIKE REPLACE(' ".$query." ',' ','%');
Note that I purposely add spaces between .$query. to ensure that the replace operation will make your term filled with the wildcard symbol. In the example above:
If $query='almond cookies' then REPLACE(' ".$query." ',' ','%') will become %almond%cookies%.
You can test the fiddle here : https://www.db-fiddle.com/f/kMzp99S8ENbTkYcW5FVdYN/0

mysql query to match sentence against keywords in a field

I have a mysql table with a list of keywords such as:
id | keywords
---+--------------------------------
1 | apple, oranges, pears
2 | peaches, pineapples, tangerines
I'm trying to figure out how to query this table using an input string of:
John liked to eat apples
Is there a mysql query type that can query a field with a sentence and return results (in my example, record #1)?
One way to do it could be to convert apple, oranges, pears to apple|oranges|pears and use RLIKE (ie regular expression) to match against it.
For example, 'John liked to eat apples' matches the regex 'apple|orange|pears'.
First, to convert 'apple, oranges, pears' to the regex form, replace all ', ' by '|' using REPLACE. Then use RLIKE to select the keyword entries that match:
SELECT *
FROM keywords_table
WHERE 'John liked to eat apples' RLIKE REPLACE(keywords,', ','|');
However this does depend on your comma-separation being consistent (i.e. if there is one row that looks like apples,oranges this won't work as the REPLACE replaces a comma followed by a space (as per your example rows).
I also don't think it'll scale up very well.
And, if you have a sentence like 'John liked to eat pineapples', it would match both of the rows above (as it does have 'apple' in it). You could then try to add word boundaries to the regex (i.e. WHERE $sentence RLIKE '[[:<:]](apple|oranges|pears)[[:>:]]'), but this would screw up matching when you have plurals ('apples' wouldn't match '[wordboundary]apple[wordboundary]').
Hopefully this isn't more abstract than what you need but maybe good way of doing it.
I haven't tested this but I think it would work. If you can use PHP you can use str_replace to turn the spaces into keyword LIKE '%apple%'
$sentence = "John liked to eat apples";
$sqlversion = str_replace(" ","%' OR Keyword like '%",$sentence );
$finalsql = "%".$sqlversion."%";
the above will echo:
%John%' OR Keyword like '%liked%' OR Keyword like '%to%' OR Keyword like '%eat%' OR Keyword like '%apples%
Then just combine with your SQl statement
SQL ="SELECT *
FROM keywords_table
WHERE Keyword like" . $finalsql;
Storing comma delimited data is... less than ideal.
If you broke up the string "John liked to eat apples" into individual words, you could use the FIND_IN_SET operator:
WHERE FIND_IN_SET('apple', t.keywords) > 0
The performance wouldn't be great - this operation is better suited to Full Text Search.
I'm not aware of any direct solution to that type of query. But Full Text Search is a possibility. If you have a full-text index on the field of interest then a search with OR between each word in the sentence (although I think the OR operator is implied) would find that record ... but it might also find more than you want too.
I really don't think what you are looking for is completely possible but you can look into Full Text Search or SOUNDEX. SOUNDEX, for example, can do something like:
WHERE SOUNDEX(sentence) = SOUNDEX('%'+keywords+'%');
I have never tried it in this context but you should and let me know how it works out.

Mysql RegExp question selecting from a list of codes

I am trying to match a list of motorcycle models to a series of ebay codes for listing motorcycles in ebay.
So we get a motorcycle model name that will be something like:
XL883C Sportster where the manufacturer is Harley Davidson
I have a list of ebay codes that look like this
MB-100-0 Other
MB-100-1 883
MB-100-2 1000
MB-100-3 1130
MB-100-4 1200
MB-100-5 1340
MB-100-6 1450
MB-100-7 Dyna
MB-100-8 Electra
MB-100-9 FLHR
MB-100-10 FLHT
MB-100-11 FLSTC
MB-100-12 FLSTR
MB-100-13 FXCW
MB-100-14 FXSTB
MB-100-15 Softail
MB-100-16 Sportster
MB-100-17 Touring
MB-100-18 VRSCAW
MB-100-19 VRSCD
MB-100-20 VRSCR
So I want to match the model name against the list above using a regExp pattern.
I have tried the following code:
SELECT modelID FROM tblEbayModelCodes WHERE
LOWER(makeName) = 'harley-davidson' AND fnmodel REGEXP '[883|1000|1130|1200|1340|1450|Dyna|Electra|FLHR|FLHT|FLSTC|FLSTR|FXCW|FXSTB|Softail|Sportster|Touring|VRSCAW|VRSCD|VRSCR].*' LIMIT 1
however when I run the query I would expect the code to match on either MB-100-1 for 883 or MB-100-16 for Sportster but when I run it the query returns MB-100-0 for Other.
I am guessing that I have the pattern incorrect, so can anybody suggest what I might need to do to correct this?
Many thanks
Graham
[chars] matches any of the characters 'c','h','a','r','s'
So by giving it such a long list, it will inevitably match just the first item (single character)
Try this instead
LOWER(makeName) = 'harley-davidson' AND fnmodel REGEXP '(883|1000|1130|1200|1340|1450|Dyna|Electra|FLHR|FLHT|FLSTC|FLSTR|FXCW|FXSTB|Softail|Sportster|Touring|VRSCAW|VRSCD|VRSCR).*' LIMIT 1
You might also consider not using REGEX and using FIND_IN_SET instead.
Not really fully tested, but it should be something like this:
REGEXP '^MB-[0-9]+-[0-9]+[[:space:]]+(883|1000|1130|1200|1340|1450|Dyna|Electra|FLHR|FLHT|FLSTC|FLSTR|FXCW|FXSTB|Softail|Sportster|Touring|VRSCAW|VRSCD|VRSCR)$'
In detail:
^MB- Starts with MB-
[0-9]+ One or more digits
- Dash
[0-9]+ One or more digits
[[:space:]]+ One or more white space
(883|1000|...)$ Ends with one of these
Here's the reference for the regexp dialect spoken by MySQL:
http://dev.mysql.com/doc/refman/5.1/en/regexp.html
Answer to comment:
If you want to match the Sportster row them remove all other conditions. And you may not even need regular expressions:
WHERE fnmodel LIKE '% Sportster'

mysql regular expression

I found this query in mysql query log and I will like to know what exactly does it do.
select * from tblname WHERE TRIM(NAME) REGEXP 'John[ ]*Smith'
It selects all rows from tblname where name (with spaces around removed, if any) equals to John<any number of spaces>Smith
So you'll find JohnSmith as well as John_________________________Smith (stackoverflow eats repetitive spaces, so I replaced them with underscore).
The regex itself is a little bloated and can be rewritten as John *Smith