Я думаю, что нахожусь в одной лодке: Я очень редко использую наборы данных, и я, конечно, не утверждаю, что был экспертом по модели адаптера (я думаю" Fill
", единственный метод, который я действительно использовал в производстве) - но у них действительно иногда есть некоторое использование. Например, если необходимо выполнить некоторый специальный код SQL, не может предсказать схему (и таким образом, ORM не помогает), и не хотят смешивать с IDataReader
и т.д. для простого, маленького набора данных.
Кроме того (т.е. большую часть времени), я предпочитаю стандартные классы - или ORM или руководство.
Выполните подзапрос:
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%'
Рассмотрим некоторые возможные входы:
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 практически невозможно.
Вы можете указать вычисляемый столбец в предложении 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 для полнотекстового индексирования.
Хотя использование подзапроса работает хорошо, оно окажет влияние, поскольку вы не попадете ни в какие индексы.
А как насчет добавления вычисляемого столбца ( firstname || '' || lastname
) к таблице и индекс к ней? Конечно, это было бы намного быстрее.
Если вы не можете этого сделать, я думаю, что запросы типа
WHERE firstname || ' ' || lastname LIKE '%user_submitted_data%'
все равно должны работать быстрее, чем два OR
s и один подзапрос.