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.
Related
So I am trying to do this:
SELECT customerID, name, email
FROM Customers
WHERE customerID IN (substrings delineated by spaces of CID string)
Where what I want to happen, is it returns the entries that have a matching customerID.
Unfortunately, the value CID is a string of all the matching CIDs separated by spaces. I've tried to change it to be some sort of list, but no luck on that end. If I could use something like string splitter that would solve my problem, but it doesn't seem to be available in MySQL.
Sorry for the relatively simple question, but an hour of googling has returned no clear answers.
I wonder if you could use the REPLACE function:
SELECT customerID, name, email
FROM Customers
WHERE customerID IN (REPLACE(CID string,' ',','))
https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_replace
One method is like:
SELECT customerID, name, email
FROM Customers
WHERE CONCAT(' ', CID, ' ') LIKE concat('% ', customerID, ' %') ;
I really do advocate that you separate the string. If it is coming from a table, then you probably need a junction/association table.
Try this:
WHERE FIND_IN_SET(CustomerID, REPLACE(spacedList, ' ', ',')) > 0
FIND_IN_SET
You might need to also cast CustomerID to a char, but I would try without the cast first.
I'm trying to join two columns of the same table but, if there are null values (in my case they are in the second column), I want to take anyway the row that interests me and, rather than putting the null value, I would put ''. The columns that I want to join are Surname and Name. In other words, I tried to use :
SELECT CONCAT(CSurname, ' ', CName)
FROM Client;
In this way if I have a valid value for surname and a null value for name I obtain null. I use MySql, thanks.
If you want to avoid the problem with a leading space, then the easiest way is probably CONCAT_WS():
SELECT CONCAT_WS(' ', CSurname, CName)
FROM Client;
Unlike most other functions, CONCAT_WS() ignores NULL values (except for the separator), greatly simplifying this logic -- particularly when you are working with more than two columns.
Without it, the equivalent logic could be expressed as:
SELECT CONCAT(COALESCE(CONCAT(CSurname, ' '), ''), COALESCE(CName, ''))
Try the ifnull function
SELECT CONCAT(CSurname, ' ', IFNULL(CName,'')) FROM Client;
I don't have a local mysql installation to try it out but the IFNULL function should achieve what you need.
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.
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.
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 :)