Skip to content
Advertisement

Query to find people with multiple names

I’m working on a fairly big project that allows users of my client’s site to search for people they used to know who might’ve changed their names, primarily due to marriage. Basically, users sign up with all the names they’ve ever used and the data gets entered into a MySQL database. The next step is actually creating the search, which allows users to put in the names they remember someone by.

This is an example registration in the database:

username first0 first1 first2 first3 first4
(email)  Lisa   John   Frank  Sam    Smith

Right now, my query looks like this:

SELECT * FROM NAMES
WHERE (
    `names`.`first0` IN ("Lisa", "Sam", "")
    AND `names`.`first1` IN ("Lisa", "Sam", "")
    AND `names`.`first2` IN ("Lisa", "Sam", "")
    AND `names`.`first3` IN ("Lisa", "Sam", "")
    AND `names`.`first4` IN ("Lisa", "Sam", "")

**Substitute out the exact names there for data entered in the search form.

This query doesn’t work because first2 = Frank, which isn’t included in the list. If a person doesn’t know every name someone entered in the database, everything breaks.

However, I don’t think I want to use OR statements, because I don’t want all the results where a name matches Lisa to be returned if someone puts Lisa as just one of the names.

Does anyone know how I could go about doing this?

Advertisement

Answer

You’re constrained unnecessarily here. Consider instead:

User
UserId, OtherData

UserNames
UserId, Name, Kind

Data like:

UserId, OtherData
1, Blahblah

UserId, Name, Type
1, Lisa, First 
1, Jane, Middle
1, Smith, Last   
1, Leese, First
1, Jones, Last

Lisa Jane Smith, also known as Leese, married and changed name to Lisa Jane Jones

If you present the website user with a “Enter any number of names and indicate their kind” you can then run a query that finds the userids that have all the name kinds mentioned

This can be as simple as dynamically joining, or doing conditional aggregation

Eg if the web user enters “Leese” as firstname and “Jones” as lastname then you can:

SELECT UserID FROM UserNames 
WHERE 
  (name = 'Leese' AND type = 'First') OR
  (name = 'Jones' AND type = 'Last')
GROUP BY
  UserID 
HAVING count(*) = 2 --2 is the number of names entered, leese and jones.  If your where clause had 5 names, this would be 5

Or you can use a join approach (and this for if the web user enters 3 names/kinds):

SELECT u1.UserID 
FROM
  UserNames u1 
  INNER JOIN Usernames u2 ON u1.UserID = u2.UserID
  INNER JOIN Usernames u3 ON u1.UserID = u3.UserID
WHERE 
  u1.name = 'Leese' AND u1.type = 'First' AND
  u2.name = 'Jones' AND u2.type = 'Last' AND
  u3.name = 'Smith' AND u3.type = 'Last' AND
  

When you go to form your dynamic queries, don’t concatenate the values into SQL. Just because you’re making a query dynamic built is not an excuse to throw parameterization out of the window. You build the SQL by concatenating together the SQL string with parameter placeholders in and then give the parameters values separately

Pseudocode (i don’t know php) in a language that interpolates its strings with {placeholders}:

string fromclause = ""
string whereclause = ""
for i = 0 to webrequest.form.values.length - 1

  string name = webrequest.form.values[i].name
  string type = webrequest.form.values[i].type


  if i == 0 then
    fromclause = fromclause + "Usernames u{i}"
  else
    fromclause = fromclause + " INNER JOIN Usernames u{i} ON u1.UserID = u{i}.UserID

  whereclause = whereclause + " u{i}.Name = @paramName{i} AND u{i}.type = @paramType{i}"

  sqlcommand.parameters.add("@paramName{i}", name)
  sqlcommand.parameters.add("@paramType{i}", type)

next i

sqlcommand.commandtext = "SELECT UserID FROM {fromclause} WHERE {whereclause}"

You finish up with a sql command that is all parameterized and the parameters are all given values..

User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement