Partial/Abbreviated Name Matching - mysql

Im trying to write a query that will match partial matches to stored name values.
My database looks as follows
Blockquote
FirstName | Middle Name | Surname
----------------------------------
Joe | James | Bloggs
J | J | Bloggs
Joe | | Bloggs
Jane | | Bloggs
Now if a user enters their name as
J Bloggs
my query should return all 4 rows, as they are all potential matches.
Similarly if a user enters the name
J J Bloggs
all rows should be returned.
If a user enters their name as
Joe Bloggs
only the first three should be returned.
I have tried the following
SELECT *
FROM PERSON
WHERE CONCAT(' ',FirstName,' ',MiddleName,' ', Surname) LIKE '% Joe%'
AND CONCAT(' ',FirstName,' ',MiddleName,' ', Surname, ' ') LIKE '% Bloggs%';
But this doesn't return 'J J Bloggs'.
Any ideas?

If I understand your logic correctly, any of the three input name components is considered to be a match if it either is a substring of a value in the table, or vice-versa. That is, J matches Joe, but also Joe matches to J. Using this logic, we can write the following query:
SELECT *
FROM yourTable
WHERE
(INSTR(FirstName, 'J') > 0 OR INSTR('J', FirstName) > 0) AND
(INSTR(MiddleName, 'J') > 0 OR INSTR('J', MiddleName) > 0 OR MiddleName IS NULL) AND
(INSTR(Surname, 'Bloggs') > 0 OR INSTR('Bloggs', Surname) > 0);
Demo
Note that the middle name has some additional logic. If the middle name be missing in a record (i.e. it is NULL), then we wave the requirement for the middle names to match.

I think you might need OR instead of AND...
SELECT *
FROM PERSON
WHERE CONCAT(' ',FirstName,' ',MiddleName,' ', Surname) LIKE '% Joe%'
OR CONCAT(' ',FirstName,' ',MiddleName,' ', Surname, ' ') LIKE '% Bloggs%';

Related

Combine "replace" and wildcards in SQL query

Within a table like this:
ID| ph_number
-----------
1 | 51231234
2 | 5123 1234
3 | 51231234; 61231234
4 | 5123 1234; 61231234
5 | 5123 1934; 6123 1234
6 | 5123 1234; 6123 1234
7 | aargh; 5123 1234; 6123 1234
, user needs to find a phone number (ex 51231234) not knowing where the spaces are, or if there are many numbers per field. I can find the numbers without spaces with query like this:
SELECT ID, ph_number FROM test WHERE REPLACE(ph_number, ' ', '') LIKE REPLACE('51231234', ' ', '')
that returns IDs 1 and 2, or
SELECT ID, ph_number FROM test WHERE ph_number LIKE '%51231234%'
that returns IDs 1 and 3. But Needed are IDs 1,2,3,4, 6 and 7. I'm not able to combine the two queries. Have tried:
SELECT ID, ph_number FROM test WHERE REPLACE(ph_number, ' ', '') LIKE ('%' + REPLACE('51231234', ' ', '') + '%') // returns 1 & 2
SELECT ID, ph_number FROM test WHERE REPLACE(ph_number, ' ', '') LIKE '%' + REPLACE('51231234', ' ', '') + '%' // returns ERROR
How could I achieve this? I wouldn't want to tell users that they can't have multiple numbers on the field.
In MySQL "+" is exclusively an arithmetic operator. Use the CONCAT() function to concatenate strings:
....WHERE REPLACE(ph_number, ' ', '') LIKE CONCAT('%', REPLACE('51231234', ' ', ''), '%')

Separate Columns with conditions

I have a table with some problem data. For example, the table is as follow :
ID NAME JOB
--- --------------------------- ---------------
1 Peter Teacher
2 John Programmer
3 Tom**He is a Teacher
4 Alan**He is a Accountant
The problem is some data has been correctly inserted but some hasn't. Now I want to execute an SQL in order to make the table looks like below :
ID NAME JOB
--- --------------------------- ---------------
1 Peter Teacher
2 John Programmer
3 Tom Teacher
4 Alan Accountant
I am not familiar with SQL Statement so I can just think of using the following PHP Script to fix this problem.
$sql1 = "SELECT NAME FROM MY_TABLE WHERE JOB = '' AND NAME LIKE '%He is a %'";
$res1 = mysql_query($sql1);
while($row1 = mysql_fetch_array($res1)){
$new_data = explode("**He is a ", $row1["NAME"]);
$sql2 = "UPDATE MY_TABLE SET NAME = '".$data[0]."', JOB = '".$data[1]."' WHERE ID = '".$data["ID"]."'";
mysql_query($sql2);
}
Can anyone suggest a better way for me to fix this problem with one or a few SQL Statement ? Thanks
UPDATE
SET NAME = SUBSTRING_INDEX(SUBSTRING_INDEX(NAME, '**He is a ', 1), ' ', -1),
job = SUBSTRING_INDEX(SUBSTRING_INDEX(NAME, '**He is a ', 2), ' ', -1)
WHERE NAME LIKE '%**He is a %'
You can use the substring_index function to break up the string, and apply all the changes in a single update statement:
UPDATE my_table
SET JOB = SUBSTRING_INDEX (name, '**He is a ', -1),
name = SUBSTRING_INDEX (name, '**He is a ', 1),
WHERE name LIKE '%**He is a %' AND
(job IS NULL OR job = '') -- Just to be on the safe side

Create search query

I have a table named Customers with columns FirstName, LastName, Email
Let's pretend I have the customer: John | Williams | johnW1234#gmail.com
Now how do I have to create my query so that if I search for:
"williams" => match
"will john" => Match
"will john 55" => NO match
"will 1234" => match
my query right now looks like:
SELECT * FROM `Customers` WHERE `FirstName` LIKE _search_ OR `LastName` LIKE _search__
But if someone where to look for "will john" then my query will return no matches
Seems like you want to do something like that:
select * from Customers where
(FirstName like concat('%','john', '%') and LastName like concat('%','smith', '%'))
or
(LastName like concat('%','john', '%') and FirstName like concat('%','smith', '%'))
The parts: john and smith (in the query) are the different parts of the search term which is exploded by spaces and modified to lowercase (you can do it either in the code or in the DB).
Link to Fiddle
I think this works:
select * from Customers
where (_search_ regexp '^[^ ]+ [^ ]+$' or _search_ regexp '^[^ ]+$')
and (LastName like concat(substring_index(_search_, ' ', 1), '%'))
or FirstName like concat(substring_index(_search_, ' ', -1), '%')));
Dynamic sql can help you
EXECUTE 'SELECT * FROM Customers WHERE FirstName LIKE ' ||
_search_ || ' OR LastName LIKE ' || _search__ || ';';
"_ search _" should be converted to text (explicitly or not).
Of course, quotation waiting for your attention.
Crudely...
SET #string = 'John|Williams|johnW1234#gmail.com';
SELECT IF(#string LIKE "%will%",IF(#string LIKE "%john%",IF(#string LIKE "%55%",1,0),0),0)x;
+---+
| x |
+---+
| 0 |
+---+
SELECT IF(#string LIKE "%will%",IF(#string LIKE "%john%",IF(#string LIKE "%12%",1,0),0),0)x;
+---+
| x |
+---+
| 1 |
+---+

sql last name comma first null checks

I have three columns in the database that represent a person's first, middle, and last names:
People
|------------------------------------------|
| First_Name | Last_name | Middle_name|
|------------------------------------------|
| John | Hansen | T |
| NULL | Smith | NULL |
| Jacob | NULL | J |
| Michael | Johnson | NULL |
|------------------------------------------|
What is the best way to get null safe Last, First Name + Middle Name. So that from the list above I would get:
Hansen, John T
Smith
Jacob J
Johnson, Michael
So far I've got:
select concat_ws(', ', name_last, concat_ws(' ', name_first, name_middle)) as name from entity;
but it's giving me trailing , where I don't want them.
You can use the fact that CONCAT will return NULL if any of the arguments are NULL:
SELECT COALESCE(CONCAT(last_name, ', ', first_name), last_name, first_name)
FROM People
SQL Fiddle Demo
Or, now that you've edited your question to add a Middle_name column:
SELECT COALESCE(CONCAT(last_name, ', ', COALESCE(CONCAT(first_name, ' ', middle_name),first_name,middle_name)),
last_name,
COALESCE(CONCAT(first_name, ' ', middle_name),first_name,middle_name))
FROM People
SQL Fiddle Demo
The other way around:
You have a fullname column containing "firstname middlename lastname"
and want to display it sorted on lastname
Made this as working, at least it works great on dutch names ("van der Boogert" but also single (artist)names.
This example trims the anmes for extra spaces, then counts the amount of spaces in the fullname so no commas are places when its only a single name (artist name)
SELECT
TRIM(fullname) as originalfullname,
length(trim(fullname)) -length(replace(TRIM(fullname), ' ', '')) AS countedzeros,
SUBSTRING_INDEX(TRIM(fullname), ' ', length(TRIM(fullname)) -length(replace(TRIM(fullname), ' ', ''))) AS first_name,
SUBSTRING_INDEX(TRIM(fullname), ' ', -1) AS last_name,
CONCAT(
SUBSTRING_INDEX(TRIM(fullname), ' ', -1),
IF(length(TRIM(fullname)) -length(replace(TRIM(fullname), ' ', '')),', ',''),
SUBSTRING_INDEX(TRIM(fullname), ' ', length(TRIM(fullname)) -length(replace(TRIM(fullname), ' ', '')))
) as dispayname
FROM catalog
group by fullname
/*
Theo van den Boogaart => Boogaart, Theo van den
Hergé => Hergé
Jhonny Smith => Smith, Johnny
*/

Reformat table data sql

I have a field name with the following rows:
`name`
------
John Smith
George Washington
Ash Ketchum
Bill O'Reilly
I would like to reformat the rows on output:
`name`
------
SMITH, JOHN
WASHINGTON, GEORGE
KETCHUM, ASH
O'REILLY BILL
I know I can use upper( x.name ) for casing, but how can I reformat the names?
Assuming your rdbms is mySql, answer will need to be tailored to differenct dialects of sql.
SELECT concat( substring(name, locate(name, ' ')), ', ', substring(name, 0, locate(name, ' ') - 1)) FROM NAMES;
The real problem here however is data integrity. You need to have seperate columns for each peice of the name so that formating in the database is ensured to be consitent. Ideally you would want to be doing this --
Select concat(last_name, ', ', first_name) FROM NAMES;
Allowing
'name'
-------------------
John Smith
Smith, John
J Smith
Smith J
John q Smith
Jhon 'the smithmeister' Smith
All in the same column of a table is a bad thing for a number of reasons so this should be explictly prevented.
Try this:
SELECT SUBSTRING_INDEX( `name` , ' ', -1 ) + ', ' + SUBSTRING_INDEX( `name` , ' ', 1 )
FROM MyTable
#Ben, makes a good point about names with multiple spaces in them. I doubt this would give you the output you want in those cases, but it should get you started.
try this
SELECT Concat(SUBSTRING_INDEX( `name` , ' ', -1 ) , ', ' , SUBSTRING_INDEX( `name` , ' ', 1 )) as name
FROM your_Table