I have a long list of names formatted like below. A person may have a few different representations of their name in the table (e.g. ‘Smith, Tom’ vs ‘Tom Smith’).
A query will come through using a like search (e.g. "SELECT * FROM table WHERE person_name LIKE "%smith%"
).
If a person has the boolean field is_display
checked as true I want only the row with is_display
set to true, if the person ID does not have an is_display
checked off, I then want to fall back on the is_preferred
field.
So ideally, a search for “smith” would only return rows 1 and 4.
ID person_id person_name is_preferred is_display
1 123456 Tom Smith 0 1
2 223456 Madonna 1 1
3 123456 Smith, Tom 1 0
4 423456 Smith, Frank 1 0
5 423456 Smith, Frank R. 0 0
I’ve looked into SQL if / else and CASE statements, but haven’t found a command that works for this need yet.
Right the closest I’ve gotten is:
SELECT *
FROM artist_aliases
WHERE ( (alias LIKE '%smith%' AND display=1) OR
(alias LIKE '%smith%' AND preferred=1) )
Then I massage the results in code after SQL. But I imagine there’s a much more elegant way to do this only in SQL.
Advertisement
Answer
You seem to want a prioritization by person.
In MySQL 8+, this would look like:
select aa.*
from (select aa.*,
row_number() over (partition by person_id order by display desc, preferred desc) as seqnum
from artist_aliases aa
where alias like '%smith%'
) aa
where seqnum = 1;
In earlier versions, you can use a correlated subquery:
select aa.*
from artist_aliases aa
where aa.alias like '%smith%' and
aa.id = (select aa2.id
from artist_aliases aa2
where aa2.alias like '%smith%' and
aa2.person_id = aa.person_id
order by aa2.display desc, aa2.preferred desc
limit 1
);