2009-08-22 4 views
5

Я пытаюсь получить записи в MySQL, используя просто используемое поле отправки. Точнее, пользователь вводит имя (имя или фамилия или полное имя), и сервер должен возвращать сопоставленные строки.Использование 'OR' между предложением HAVING и WHERE в MySQL?

То, что я делал до сих пор что-то вроде:

SELECT * FROM people 
WHERE 
    firstname LIKE '%user_submitted_data%' OR 
    lastname LIKE '%user_submitted_data%' 

Это хорошо работает сейчас, но это (очевидно) не будет работать, когда пользователь отправляет FULLNAME. Есть ли способ добавить OR между целыми условиями типа WHERE и условиями типа HAVING? Таким образом, я мог бы сделать что-то вроде:

SELECT [some fields], CONCAT(firstname, ' ', 'lastname') as fullname 
FROM people 
WHERE 
    firstname LIKE '%user_submitted_data%' OR 
    lastname LIKE '%user_submitted_data%' OR 
    HAVING fullname LIKE '%user_submitted_data%' 

Я знаю, что я мог бы просто разделить исходную строку, но это имеет некоторые негативные последствия, так как вы должны иметь дело с именами, содержащими пробелы, такие как «De Gaule» и тому подобное.

ответ

4

ли подзапрос:

SELECT [some fields] 
FROM 
    SELECT firstname, lastname, CONCAT(firstname, ' ', lastname) as fullname 
    FROM people) AS tmp 
WHERE firstname LIKE '%user_submitted_data%' 
OR lastname LIKE '%user_submitted_data%' 
OR fullname LIKE '%user_submitted_data%' 
+0

Спасибо, исправляет. – Jimmy

1

Рассмотрим некоторые возможные входы:

John 
Smith 
John Smith 

Ваш первоначальный пример запроса является:

SELECT * FROM people 
WHERE 
    firstname LIKE '%user_submitted_data%' OR 
    lastname LIKE '%user_submitted_data%' 

Теперь, когда пользователь входит в первый вход , этот запрос выберет всех людей, чье имя содержит «Джон»; он также отобрат всех людей, чья фамилия содержит «Джон» (например, все Джонсоны в базе данных). Аналогичным образом, второй вход будет выбирать всех людей, чье имя содержит «Смит»; он также отобрат всех людей, чья фамилия содержит «Смит» (например, Смитсоны и Смитерс). Все идет нормально; он не идеален из-за проблем с чувствительностью к регистру (я буду игнорировать чувствительность к регистру отсюда, но вы, вероятно, не должны игнорировать его вообще), но все будет в порядке.

Третий вход будет выбирать только людей, чье имя содержит «Джон Смит»; он также отобрат тех людей, чья фамилия содержит «Джон Смит». Однако весьма вероятно, что очень мало людей, которые отвечают этим критериям - те, кого называют Джоном Смитом, будут иметь только Джона от первого имени и только Смита в фамилии. Это вряд ли будет тем, что вы имели в виду.

Неясно, есть ли в таблице столбец с именем «полное имя». Если вы это сделаете, вы можете просто сопоставить этот столбец, а не сопоставлять его с именем и фамилией отдельно. Если вы этого не сделаете, возможно, вы можете создать такой столбец, а затем запустить запрос.

SELECT * 
    FROM (SELECT firstname || ' ' || lastname AS fullname, ... FROM people) AS t 
WHERE t.fullname LIKE '%user_submitted_data%' 

Это работает достаточно хорошо.

Однако, если вас беспокоят такие имена, как «Шарль де Голль» (или «Шарль де Голль») или «Майкл ван ден Берг»), то совпадение потерпит неудачу, если кто-то войдет в «Шарль Голль» или «Шарль де Голль», Майкл Берг, не говоря уже о Майкле Ванденберге. Вам, вероятно, потребуется заменить любые символы пробела в пользовательском вводе символом «%». Даже тогда вы сталкиваетесь с проблемой, что слова должны отображаться точно в последовательности, заданной пользователем - что может быть неважно, но вы должны сознательно решить, что это не имеет значения. Например, если ввод «Адам Джон Смит», тогда запрос не поймает «Джон Адам Смит»; если вход «Смит, Джон», то он никого не поднимет (скорее всего).

Если вы хотите управлять этим, вам, вероятно, нужно будет токенизировать вход пользователя и выполнять поиск по отдельным словам.Остерегайтесь того, что кто-то спрашивает о подстроке слова (например, кто-то спрашивает об «de» в качестве имени) - ни один из запросов на данный момент не гарантирует, что пользовательские слова ввода соответствуют целым словам в значениях (John vs Johnson), и сделать это с помощью стандартного оператора LIKE SQL почти невозможно.

+0

Спасибо за углубленный тент. По какой-то причине, похоже, что MySQL не чувствителен к регистру в моей системе (OSX), поэтому до сих пор он работал отлично. Что касается порядка слов, оператор LIKE очень хорошо подходит к контексту. Мне не нужно (и не хочу) Джох Смита выходить, когда пользователь ищет Джона Адама Смита. Пример поиска довольно ограничен. – Jimmy

0

Вы можете ссылаться на вычисляемый столбец в предложении WHERE если определить, что столбец в подзапрос:

SELECT p.* 
FROM (
    SELECT [some fields], CONCAT(firstname, ' ', 'lastname') as fullname 
    FROM people 
) p 
WHERE 
    p.firstname LIKE '%user_submitted_data%' OR 
    p.lastname LIKE '%user_submitted_data%' OR 
    p.fullname LIKE '%user_submitted_data%'; 

Но, честно говоря, для типа поиска вы делаете, LIKE с групповым символом является страшным решением , Вы должны думать об использовании FULLTEXT индекса:

CREATE FULLTEXT INDEX people_names ON people(firstname, lastname); 

SELECT * 
FROM people 
WHERE MATCH(firstname, lastname) AGAINST(?); 

PS: FULLTEXT индексы работают только с двигателем хранения MyISAM. Еще одно решение, еще более быстрое, - использовать Sphinx Search для полнотекстового индексирования.

0

Хотя использование подзапроса работает хорошо, оно будет иметь влияние, потому что вы не нажимаете на какие-либо индексы.

Как насчет добавления вычисленного столбца (firstname || ' ' || lastname) в таблицу и указателя на него? Конечно, это было бы намного быстрее.

Если вы не можете сделать это, я думаю, что запрашивая как

WHERE firstname || ' ' || lastname LIKE '%user_submitted_data%' 

должно работать быстрее, чем два OR с и один подзапроса.

+0

Я не думаю, что есть способ сделать индексированный столбец вычислений в MySQL или показать мои исследования. Если это выполнимо, я бы хотел услышать об этом. – Jimmy

+0

Возможно, вы правы, я думаю, что нет возможности использовать вычисленные столбцы вообще !? – Sklivvz

+0

Между тем MySQL поддерживает индексированные вычисленные столбцы. Но LIKE условия не могут использовать индекс, если шаблон начинается с заполнителя ('%'). –

7

Просто поместите все условия в статью HAVING.

SELECT [some fields], CONCAT(firstname, ' ', 'lastname') as fullname 
FROM people 
HAVING firstname LIKE '%user_submitted_data%' 
OR  lastname LIKE '%user_submitted_data%' 
OR  fullname LIKE '%user_submitted_data%

Предложение WHERE может удалить строки в начале, но так как вы не можете отказаться от них до после вы оценивали состояние на вычисляемого столбца, и есть не ждать, пока HAVING, он не покупает вам ничего, чтобы использовать WHERE ,

+0

Работала для меня, кажется гораздо более элегантным решением, чем использование подзапросов. Спасибо! –

Смежные вопросы