Используя 'ИЛИ' между НАЛИЧИЕМ и оператором Where в MySQL?

Я думаю, что нахожусь в одной лодке: Я очень редко использую наборы данных, и я, конечно, не утверждаю, что был экспертом по модели адаптера (я думаю" Fill", единственный метод, который я действительно использовал в производстве) - но у них действительно иногда есть некоторое использование. Например, если необходимо выполнить некоторый специальный код SQL, не может предсказать схему (и таким образом, ORM не помогает), и не хотят смешивать с IDataReader и т.д. для простого, маленького набора данных.

Кроме того (т.е. большую часть времени), я предпочитаю стандартные классы - или ORM или руководство.

6
задан Jonathan Leffler 22 August 2009 в 18:12
поделиться

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%'
5
ответ дан 8 December 2019 в 14:45
поделиться

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

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 Джонсон), а сделать это с помощью стандартного оператора SQL LIKE практически невозможно.

1
ответ дан 8 December 2019 в 14:45
поделиться

Вы можете указать вычисляемый столбец в предложении 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
ответ дан 8 December 2019 в 14:45
поделиться

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

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

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

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

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

0
ответ дан 8 December 2019 в 14:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: