MySQL search within the last 5 characters in a column? - mysql

My user table has a column "name" which contains information like this:
Joe Lee
Angela White
I want to search for either first name or last name efficiently. First name is easy, I can do
SELECT * FROM user WHERE name LIKE "ABC%"
But for last name, if I do
SELECT * FROM user WHERE name LIKE "%ABC"
That would be extremely slow.
So I am thinking about counting the characters of the input, for example, "ABC" has 3 characters, and if I can search only the last three characters in name column, that would be great. So I want something like
SELECT * FROM user WHERE substring(name, end-3, end) LIKE "ABC%"
Is there anything in MySQL that can do this?
Thanks so much!
PS. I cannot do fulltext because our search engine doesn't support that.

The reason that
WHERE name LIKE '%ith'
is a slow way to look for 'John Smith' by last name is the same reason that
WHERE Right(name, InStr(name, ' ' )) LIKE 'smi%'
or any other expression on the column is slow. It defeats the use of the index for quick lookup and leaves the MySQL server doing a full table scan or full index scan.
If you were using Oracle (that is, if you worked for a formerly wealthy employer) you could use function indexes. As it is you have to add some extra columns or some other helping data to accelerate your search.
Your smartest move is to split your first and last names into separate columns. Several other people have pointed out good reasons for doing that.
If you can't do that you could try creating an extra column which contains the name string reversed, and create an index on that column. That column will have, for example, 'John Smith' stored as 'htimS nhoJ'. Then you can search as follows.
WHERE nameReversed LIKE CONCAT(REVERSE('ith'),'%')
This search will use the index and be decently fast. I've had good success with it.

You're close. In MySQL you should be able to use InStr(str, substr) and Right(str, index) to do the following:
SELECT * FROM user WHERE Right(name, InStr(name, " ")) LIKE "ABC%"
InStr(name, " ") returns the index of the Space character (you may have to play with the " " syntax). This index is then used in the Right() function to search for only the last name (basically; problems arise when you have multiple names, multiple spaces etc). LIKE "ABC%" would then search for a last name starting with ABC.
You cannot use a fixed index as names that are more than 3 or less than 3 characters long would not return properly as you suggest.
However, as Zane said, it's a much better practise to use seperate fields.

If it is a MyIsam table, you may use Free text search to do the same.

You can use the REGEXP operator:
SELECT * FROM user WHERE name REGEXP "ABC$"
http://dev.mysql.com/doc/refman/5.1/en/regexp.html

Related

Search comma separated string using LIKE in mysql

I have a table with 3 columns something like below,
expert table
id - 1589
name - Jhonny
expert_in - 1,12,8 (Values similar like this)
The experts_in contains another table's foreign key
experts_in table
id - 1
expert_in - painting
I want search experts who are expert in some jobs while searching for experts
SELECT * FROM `experts` WHERE expert_in LIKE 1%
The above query brings all experts with 11,12,13...etc. I want only exact word. I know LIKE will bring all. Is there any way to achieve this without altering table. Thanks in advance.
You should use REGEXP. Try this query:
SELECT * FROM experts
WHERE expert_in REGEXP '[[:<:]]1[[:>:]]';
Output: See Live Demo on SQLFiddle
Note: You can adjust searching string based on your requirement above REGEXP is searching exact word.
if you can alter the data (not the table/schema) you should append and prepend another comma, so you can search with where col like "%,123,%", this will always fit on an exact value. Otherwise you have to use regex with something like ,?123,?

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 UNION query correct handling for 3 or more words

I've to ask your help to solve this problem.
My website has a search field, let's say user writes in "Korg X 50"
In my database in table "products" i have a filed "name" that holds "X50" and a field "brand" that hold "Korg". Is there a way to use the UNION option to get the correct record ?
And if the user enters "Korg X-50" ?
Thank you very much !
Matteo
May be you should use full-text search
SELECT brand, name, MATCH (brand,name) AGAINST ('Korg X 50') AS score
FROM products WHERE MATCH (brand,name) AGAINST ('Korg X 50')
As far as I understand you don't need UNION but something like
SELECT * FROM table1
WHERE CONCAT(field1, field2) LIKE '%your_string%'
On client side you get rid of all characters (like space, hyphen, etc) in your_string that appears in user input and cannot be in field1 or field2.
So, user input Korg X 50 as well as Korg X-50 becomes KorgX50.
you will need to get some form of searchable text.
either parse out the input for multiple key words and match each separately, or perhaps try to append them all together and match to the columns appended in the same way.
you will also need either a regex, or maybe a simpler search and replace to get rid of spaces and dashes after the append before the comparison.
in general, allowing users to search for open ended text strings is more complicated than 'what union do i use'... you will ideally also be worried about slight misspellings and capitalization, and keyword order.
you may consider pulling all keywords out from your normal record into a separate keyword list associated with each product, then use that list to perform your searches.
If you do not want to parse user input and use as it is, then you will need to use a query like this
select * from products where concat_ws(' ',brand,name) = user_input -- or
select * from products where concat_ws(' ',brand,name) like %user_input%
However, this query won't return result if user enters name "Korg X-50" and your table contains "Korg" and "X50", then you need to do some other thing to achive this. You may look at http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_soundex however it won't be a complete solution. Look for text indexing libraries for that ex: lucene

Use REGEXP in MySQL to match keywords for search engine in random order

I'm trying to use a regular expression to match a user entered search string to a title of an entry in my MySQL database.
For example I have the following rows in a table in my databse:
id title
1 IM2 - Article 3 Funky Business
2 IM2 - Article 4 There's no Business That's not Show Business
3 IM2 - There's no Business That's not Show Business
4 CO4 - Life's a business
When a user searches for "IM Article Business", the following query will be executed (spaces are replaced by "(.*)" using str_replace):
SELECT * FROM mytable WHERE title REGEXP 'IM(.*)Article(.*)Business'
This will return the first 2 rows.
Now, I want it to show the same results when a user uses the same words, but in another order, for example: "Business IM Article". The results MUST contain all words entered, only the order of how the words are entered shouldn't matter.
I couldn't figure out how to do it in any way and hoped regular expressions would be the answer. I've never used them before, so does anybody know how to do this?
Thanks,
Pascal
This isn't something regular expressions are great at. Fortunately, it's something SQL is pretty good at. (I'm going to not use mysql's regexp keyword, which I didn't even knew existed, and instead use the SQL standard "%" glob matching.)
select * from mytable where title like '%IM%' and title like '%Article%' and title like '%Business%'
Now title has to contain all three strings, but you haven't specified an order. Exactly what you want.

MySQL query - select postcode matches

I need to make a selection based on the first 2 characters of a field, so for example
SELECT * from table WHERE postcode LIKE 'rh%'
But this would select any record that contains those 2 characters at any point in the "postcode" field right? I am in need of a query that just selects the first 2 characters. Any pointerS?
Thanks
Your query is correct. It searches for postcodes starting with "rh".
In contrast, if you wanted to search for postcodes containing the string "rh" anywhere in the field, you would write:
SELECT * from table WHERE postcode LIKE '%rh%'
Edit:
To answer your comment, you can use either or both % and _ for relatively simple searches. As you have noticed already, % matches any number of characters whereas _ matches a single character.
So, in order to match postcodes starting with "RHx " (where x is any character) your query would be:
SELECT * from table WHERE postcode LIKE 'RH_ %'
(mind the space after _). For more complex search patterns, you need to read about regular expressions.
Further reading:
http://dev.mysql.com/doc/refman/5.1/en/pattern-matching.html
http://dev.mysql.com/doc/refman/5.1/en/regexp.html
LIKE '%rh%' will return all rows with 'rh' anywhere
LIKE 'rh%' will return all rows with 'rh' at the beginning
LIKE '%rh' will return all rows with 'rh' at the end.
If you want to get only first two characters 'rh', use MySQL SUBSTR() function
http://dev.mysql.com/doc/refman/5.1/en/string-functions.html#function_substr
Dave, your way seems correct to me (and works on my test data). Using a leading % as well will match anywhere in the string which obviously isn't desirable when dealing with postcodes.