Match single input and two database fields - mysql

i'm building a search form for a website, with a single input fields (name and lastname) and i need it to match against two database fields (NAME_FIELD and LNAME_FIELD).
Obviously users can type in the name first or the lastname (or only the lastname) as they prefer.
Thank you

Assuming the user inputs are NULL when not used:
select *
from YourTable
where NAME_FIELD = coalesce(#name, NAME_FIELD)
and LNAME_FIELD = coalesce(#lastname, LNAME_FIELD)

Assuming you are using prepared statements:
WHERE (:name IS NULL OR NAME_FIELD LIKE :name)
OR (:lname IS NULL OR LNAME_FIELD LIKE :lname)
Have a look at MyISAM Full Text Search, which will lead to much better performance then the LIKE operator.

The syntax may be off a bit, but you could do something like:
WHERE 'name_field' LIKE %'YOUR_INPUT'% OR 'lname_field' LIKE %'YOUR_INPUT'%
You can use = 'YOUR_FIELD' to match it exactly.

Related

Need to create a custom query

I need to clear out invalid users created by a scipted attack from the database.
The query would:
check if row name "about:me" contains "michael kors"
if yes, then set row "account_status" to "inactive"
I'm a very novice "DBA" so I'm hoping an example of a correct query in this case will help me to be able to construct others and help other users do the same.
If the column name is really about:me (a colon would be unusual), and account_status is actually a text field (not an integer indicating active/inactive), and imagining your table is named users (you didn't say), something like this would work:
update users
set account_status = 'inactive'
where `about:me` like '%michael kors%';
The backticks allow unusual characters like : to appear in the column name; the % allows varying whitespace (or other random characters) around the name when used with like; the like also allows us to match regardless of upper/lowercase in the name column.
assuming you're describing a table 'tbl' with fields 'about:me' and 'account_status', you should be able to run an UPDATE with a WHERE to do this. Something like...
UPDATE tbl
SET account_status = 'inactive'
WHERE `about:me` LIKE '%michael kors%';
Note this uses LIKE which means it's case insensitive and uses the wildcard character % to match anything containing michael kors.
Hope it helps!

MySQL search within the last 5 characters in a column?

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

Match a longer string with a shorter one

I have a form where users can search all the entries in a table and i'm having problems with a specific entry.
I'll give an example for a better understanding:
The user can check 5 boxes: 1, 2, 3, 4, 5 and he checks all the boxes.
If the specific row has the value '1|2|3', my search query won't find it.
Beforehand i get the post variable in php (which is an array) and add '%' before and after every value. In this case: '%1%2%3%4%5%'
My search query:
SELECT id FROM table WHERE string LIKE '%1%2%3%4%5%'
In this case, it won't find the row with the value '1|2|3'.
I guess it's normal this way and it works great the other way around but I want to perform a query that matches parts of the original string. In my case '%1%2%3%4%5%' to match '1|2|3'.
How can i do this?
Thanks in advance for taking the time.
EDIT: Can i do this without multiple AND, OR operators?
just change it to this:
string LIKE '%1%'
OR
string LIKE '%2%'
OR
string LIKE '%3%'
...
this would solve your problem - but you should really think about normalizing your database (in this case, store 5 different flags as 1/0 for the five different settings instead of putting them all together in one field).
Before you find something sexier and more efficient, you can use:
SELECT id FROM table WHERE string LIKE '%1%' OR string LIKE '%2%' OR string LIKE '%3%' OR string LIKE '%4%' OR string LIKE '%5%'
I would say - dont use like, use substring or some similar function.

MySQL like reversed

I'm trying to get around pulling all the data from a table, and cycling through it with php. Here's my current Query:
SELECT
*
FROM
ExampleTable
WHERE
StringContains LIKE "%lkjlkjsomeuser#example.comjkjhkjhkjhkjhk,mniu,mk,mkjh%"
ExampleTable.StringContains has values that look like 'someuser#example.com', 'someuser2#example.com', etc.
This doesn't match because LIKE only finds sub strings of the column value, not the other way around. Any ideas on commands to find rows where the table value is a substring of the passed string?
SELECT
*
FROM
ExampleTable
WHERE
'lkjlkjsomeuser#example.comjkjhkjhkjhkjhk,mniu,mk,mkjh' LIKE
CONCAT('%', StringContains, '%')
Try this:
SELECT *
FROM ExampleTable
WHERE "lkjlkjsomeuser#example.comjkjhkjhkjhkjhk,mniu,mk,mkjh" LIKE
CONCAT("%",StringContains,"%")
The key is to recognize that the column variable just represents a string, and the LIKE statement is always comparing two strings in the form
"stringA" LIKE '%stringB%'
Usually people use it to search for a "part" of a string contained in the "whole" database field string, but you can easily switch them. The only extra tool you need is the CONCAT statement, since you want the database field to be the part instead of the whole. The CONCAT statement builds a string with the %'s around the database field string, and the string form of the argument is now equivalent to
"stringB" LIKE "%stringA%"
Just make the LIKE in the opposit order. Since you have to add those % you'll have to concatenate the field first:
SELECT *
FROM ExampleTable
WHERE "lkjlkjsomeuser#example.comjkjhkjhkjhkjhk,mniu,mk,mkjh" LIKE CONCAT('%', StringContains, '%');

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