Database - the best way, how to search names - mysql

I am solving in these days following situation:
In my DB table I have columns for name and surname.
On my page I have input for searching people, and I am struggling with a problem, how to search the name in database that is stored in two columns and I have the name as string ("Joe Green").
For example, in database I have followings:
Joe New
Joe Blue
Joe Green
Joe Francois Green
What could be the best way, how this problem to solve? I am currently working with MySQL database and Rails 3.
EDIT: Thank you guys for you replies, but I don't know, how to make the query in Rails 3 notation, is it possible to use "concat"?

if your database table engine is myISAM then use FULLTEXT search
first create FULLTEXT index by
CREATE FULLTEXT INDEX fx_name ON pages (name, surname)
then use below query to retrieve required data
SELECT *
FROM table
WHERE MATCH(name,surname) AGAINST ('keyword' IN BOOLEAN MODE)
update
alternative:use CONCAT
first create index
CREATE INDEX users_firstandlast ON users(name, surname);
option1: repeat the CONCAT in your WHERE clause (because AS doesn't create a name you can use in the WHERE clause):
SELECT CONCAT(name, ' ', surname) as fullname
FROM users
WHERE CONCAT(name, ' ', surname) LIKE '%joe green%';
option 2:
SELECT CONCAT(name, ' ', surname) as fullname
FROM users
WHERE name LIKE '%joegreen%' or surname LIKE '%joegreen%';
More information

A lot of this would be significantly simpler if you had given some indication of what language is being used at the interface between the input and the database (since Rails is usually associated with Ruby I'll assume you mean that), however....
SELECT *
FROM yourtable
WHERE CONCAT(name, ' ', surname)
LIKE CONCAT('%',REPLACE(?,' ', '%'),'%')
ORDER BY LEVENSTEIN(CONCAT(name, ' ', surname), ?)
(where '?' is replaced by your search string, and the levenstein function is described here)
Performance will be poor - a better solution would be to split the string Ruby and attempt matches of varying combinations.

One way is:
* split user's input to words
* search each word in name and surname columns

first use the split function to split the string
namearr = name.split
namestr = ""
namearr.each do |i|
namestr = namestr + i
end
then use the values in your query
stmt = "select * from mytable where CONCAT(firstname,surename)= " + namestr

you can use the sql server full text search which i do not recommend because of the performance is very bad ,or use the lucin .net which is more powerful and her are some links :
http://incubator.apache.org/lucene.net/
http://msdn.microsoft.com/en-us/library/ms142571.aspx
mark as answered if it helps :)

Related

How can we write following mysql query in mongodb? I need to search a text by ignoring some characters from username field stored in users collection

SELECT * FROM users WHERE REPLACE(username, '.', '_') = 'username_without_dots'
I read about $replaceAll but it is not helping.
In my query, first I am replacing existing record and then comparing, e.g there are usernames like
harry.potter
j.k rowling,
robert downy jr.
so what will happen is that DOTs(.) in these names will be replaced by UNDERSCORE( _ ) so the result will be:
harry_potter
j_k rowling,
robert downy jr_
after that comparing with searched string.
So lets say I am searching harry_potter
SELECT * FROM users WHERE REPLACE(username, '.', '_') = 'harry_potter'
Output will be:
harry.potter
Maybe try this:
db.users.find({$and:[{"username":/^[^.]*$/},{"username":"username_without_dots"} ] } )

Where statement that will use a concat

SELECT zlec_status.nazwa AS Status,
piorytet.nazwa AS Priorytet,
Concat(koord.imie, ' ', koord.nazwisko) AS `Koordynator`,
Concat(zlec_adresy.town, ' - ', zlec_adresy.street, ' ',
zlec_adresy.other)
AS `adres`,
zlec_z_dnia,zlec_id,
zlec_nr,
zlec_do,
zlec_ogran,
awizacje,
awizacja_na_dzien,
termin_zamkniecia,
tresc,
uwagi
FROM zlec
INNER JOIN koord
ON zlec.koord = koord.id
INNER JOIN zlec_adresy
ON zlec.zlec_addres = zlec_adresy.id
INNER JOIN piorytet
ON zlec.priorytet = piorytet.id
INNER JOIN zlec_status
ON zlec.status_zlecenia = zlec_status.id
WHERE `zlec_adresy`.`town` LIKE '%Sz%' LIMIT 0, 10
The table zlec_adresy is the following:
=============================
id | street | town | other
=============================
As you see there is a concat for the whole address part
Concat(zlec_adresy.town, ' - ', zlec_adresy.street, ' ',zlec_adresy.other)AS `adres`
Starting off - the user has a input field with the address lookup - so he can write either the town name or a street name or the other condition. In my code there will be only filtered through the WHERE clause of the .'town' LIKE userinput. But how can I make it working => Where ||Concat(zlec_adresy.town, ' - ', zlec_adresy.street, ' ',zlec_adresy.other)ASadres|| LIKE userinput
So basically it would filter the As adres for the where statement. Is that possible to do? Or there is another way to accomplish it.
Another, possibly more clean approach uses OR:
WHERE
town like concat('%',#userinput,'%')
OR
street like concat('%',#userinput,'%')
OR
other like concat('%',#userinput,'%')
WHERE
Concat(zlec_adresy.town, ' - ', zlec_adresy.street, ' ',
zlec_adresy.other) like concat('%',#variable,'%')
You can use HAVING to solve your issue. Something like :
SELECT
name, CONCAT(street, ' ', town) AS address
FROM
zlec
WHERE
zlec.town like '%abc%'
HAVING address like '%xyz%'
The query anatomy looks like this:
it handles the from, because all the other clauses are dependent on it
it handles the where, to filter out unneeded rows
it handles the select, so you will get the columns you want
Note, that I did not mention group by, having or order by, since they are not part of your query, so this anatomy is quite a simplified one. The purpose of this simplification was to achieve clarity.
Now, since the select runs after the where, you cannot use the renames from the select in the where, since when the where is executed, the selection was not yet executed.
So you have to do a work-around:
- you can define a temporary new relation by (select ...) mynewrelation and use the column renamings of the newrelation, but it is not advisable for this very situation. However, it is good to know about this option, it might be useful in the future
- you can use something like the one suggested by Madhivanan, but that solution is not performant, since you are doing very slow string operations to concatenate those fields. As a result, the code will be clear but slow
- Hanno Binder's solution is much better, since it uses the benefit of the or of not evaluating the second operand if the first was true. His code is fast, but you do not want to see it
My suggestion: You should define a stored function to make this calculation. That stored function should be equivalent to the solution suggested by Hanno Binder and you would just call that function in your query. So, your source-code will be clear, easy-to-read, correct and performant.

How to separate a comma separated name field in MySQL in to first name, middle name, last name and fullname?

I have a NAME column and the data is stored like this in a MySql database:
Doe,John P
I would like to break it out into FNAME LNAME MNAME and FULLNAME.
If I don't want to tamper with the SQL table, should I create a view?
I know how to fix it in PHP with a function but I would rather the processing be done on the database server than the application server.
This is what I have so far. I thinking I need a compound query or something similar.
SELECT Name
, SUBSTRING_INDEX(Name,',',-1) As FNAME
, SUBSTRING_INDEX(Name,',',1) As LNAME
, SUBSTRING_INDEX(Name,' ',1) As MNAME
FROM people;
I'm having trouble grabbing the middle name and doing what I think should be CONCAT function to get FULLNAME.
It would be great if there was a way (maybe a conditional) to handle names in the database that didn't have middle names. (i.e. DOE,JOHN).
A view is a fine way to get the results you want for future queries. The defining query would be:
SELECT Name, SUBSTRING_INDEX(SUBSTRING_INDEX(Name, ',', -1), ' ', 1) As FNAME,
SUBSTRING_INDEX(Name, ',', 1) As LNAME,
SUBSTRING_INDEX(Name, ' ', -1) As MNAME
FROM people;
This will work assuming that the format is exactly correct as you describe it in the table. Small changes -- such as no middle name or a space after the comma -- would make the syntax more complicated.

How to search with firstname and last name in - Mysql

Consider I am having tow fields in my table
field_profile_first_name_value field_profile_last_name_value
Victor Brecher
Abhi Jass
select field_profile_first_name_value, field_profile_last_name_value
from content_type_profile where field_profile_first_name_value LIKE '%Victor Bre%' OR
field_profile_last_name_value LIKE '%Victor Bre%'
I am having a auto complete text box.
When i enter the keyword as victor it will fetch the result. But if i give the first name and last name in the same time it will not produce the result.
That is if i give the keyword as Victor Brecher it will not produce the result.
How can i make to get the result if i enter first name and last name ?
How can i make it ?
Try :
select * from contracts
where lower(concat_ws(' ', field_profile_first_name_value, field_profile_last_name_value))
like lower('%Victor Bre%')
Well, even you don't need to use lower too. just use it simply.
select * from contracts where concat_ws(' ', field_profile_first_name_value,field_profile_last_name_value)
like '%Victor Bre%'
I would make use of soundex.
select * from contracts where SOUNDEX(concat_ws(' ', field_profile_first_name_value,field_profile_last_name_value)) = SOUNDEX('Victor Bre');
I suggest to use this code, so the search works also if the search input is the lastname before the name
SELECT
*
FROM
contracts
WHERE
CONCAT(firstname, ' ', lastname)) LIKE 'Victor Bre%'
OR CONCAT(lastname, ' ', firstname)) LIKE 'Victor Bre%';
Moreover, I tested this sql code with and without LOWER(), in mysql 5.7+ the search already do that.

MySQL Search Query on two different fields

I need to search on two fields using LIKE function and should match also in reverse order. My table uses InnoDB which dont have Full text search.
Consider the following case:
I have users table with first_name and last_name column. On it, there is a row with the following value:
{
first_name: 'Ludwig',
last_name: 'van Beethoven',
}
Cases:
Can search "Ludwig van Beethoven"
Can search "Beethoven Ludwig"
Can search "Ludwig"
Can search "Beethoven"
I tried this SQL statement but no luck.
SELECT CONCAT(first_name, ' ', last_name) as fullname
FROM users
WHERE fullname LIKE '%Ludwig van Beethoven%';
You need to re-state the concat expression in your where clause.
SELECT CONCAT(first_name, ' ', last_name) as fullname
FROM users
WHERE CONCAT(first_name, ' ', last_name) LIKE '%doe%';
Unfortunately "as" just create a column alias, not a variable that you can use elsewhere.
The Main Thing
Make sure you have a compound index on first_name and last_name. Otherwise, it's really easy to end up doing a full table scan regardless of how you approach this. So if you don't already have one, create one:
CREATE INDEX users_firstandlast ON users(first_name, last_name);
Syntax Options
Once that index is in place, you have some options:
Option 1: As Willis Blackburn said, repeat the CONCAT in your WHERE clause (because AS doesn't create a name you can use in the WHERE clause):
SELECT CONCAT(first_name, ' ', last_name) as fullname
FROM users
WHERE CONCAT(first_name, ' ', last_name) LIKE '%doe%';
Use EXPLAIN to check in your specific situation, but in my tests it says it uses the compound index, even though you're using a function in the WHERE clause.
Option 2: In this particular case, you can always just use two LIKE s in your WHERE clause:
SELECT CONCAT(first_name, ' ', last_name) as fullname
FROM users
WHERE first_name LIKE '%doe%' or last_name LIKE '%doe%';
Again this can make use of the compound index (whereas it won't make use of individual indexes on the first_name and last_name columns -- it would if you weren't leading with a wildcard, but according to EXPLAIN [and your mileage may vary, always check], in that case it goes with the table scan).
Option 3 In his answer, Andy says you can use HAVING for this. My read of the MySQL manual suggests it will first build the result set, and only then apply HAVING at the very end before sending it to the client, and so I'd be leery of this. But, in my quick and dirty tests, EXPLAIN tells me that if you have the compound index I mentioned above, the HAVING version does an index search, not a table scan. If your tests with real data bear that out, that may be a good option for you. This use of HAVING in this way is a MySQL extension (not standard), but then again, so is CONCAT so we're already into MySQL-specific stuff. :-) But again, double-check in your real life environment.
Conclusion
Create the index if you don't already have it, then I'd go with Option 2 if it's remotely a possibility; otherwise, option 1 unless you can find (or Andy can provide) a reference for the HAVING thing not building a massive interim result set (it would be really cool, if non-standard, if it didn't). Regardless, check with EXPLAIN, and test, in your specific environment.
SELECT * FROM users WHERE CONCAT(first_name, ' ', last_name) LIKE '%Ludwig%' OR CONCAT(last_name, ' ', first_name) LIKE '%Ludwig%';
All search cases where returned including 'Beethoven Ludwig'.
When you CONCAT() two columns the LIKE become case sensitive. So this should find you results but isn't optimal for performance:
SELECT CONCAT(first_name, ' ', last_name) AS fullname FROM users
WHERE LOWER(CONCAT(first_name, ' ', last_name)) LIKE LOWER('%doe%');
That's getting MySQL to do work on each row though.