дополнительные поисковые параметры в запросе SQL и строках с нулевыми значениями

Хорошо вот моя проблема:

Прежде чем я запущу описание, позвольте мне, чтобы сказать Вам, что я погуглил много, и я отправляю этот вопрос для хорошего оптимального решения :)

я создаю сервис отдыха на WCF для получения профилей пользователей... пользователь может отфильтровать профили пользователей путем предоставления чего-то как профили пользователей? location=London

теперь у меня есть следующий метод

GetUserProfiles(string firstname, string lastname, string age, string location)

строка запроса SQL, которую я создал: select firstname, lastname, .... from profiles where (firstName like '%{firstname}%') AND (lastName like '%{lastName}%') .... и так далее со всеми переменными, заменяемыми строковым средством форматирования.

Проблема с этим состоит в том, что это фильтрует любую строку, имеющую firstname, lastname, возраст или местоположение, имеющее нулевое значение....

выполнение чего-то как (firstName like '%{firstName}%' OR firstName IS NULL) было бы утомительно, и оператор станет unmaintanable! (в этом примере существует только 4 аргумента, но в моем фактическом методе существует 10),

Каково было бы лучшее решение для этого?.... Как эта ситуация обычно обрабатывается?

Database использовал: MySql

6
задан Glenn Danthi 12 March 2010 в 07:12
поделиться

4 ответа

Вы можете использовать COALESCE (значение, ...)

coalesce(firstName, '') like '%{firstname}%'
1
ответ дан 17 December 2019 в 18:13
поделиться

Вы всегда можете вообще запретить нулевые значения - в конце концов, все должны быть живы в течение некоторого положительного числа лет и находиться где-то географически.

Если вы абсолютно должны разрешить нули, используйте либо COALESCE , как предлагали другие, либо, возможно, IFNULL , который специфичен для MySQL и может быть немного более оптимальным, поскольку занимает ровно 2 параметры.

0
ответ дан 17 December 2019 в 18:13
поделиться

Вы можете использовать COALESCE :

select firstname, lastname, ....
from profiles
where (coalesce(firstName, '') like '%{firstname}%')
AND (coalesce(lastName, '') like '%{lastName}%')
0
ответ дан 17 December 2019 в 18:13
поделиться

Это фундаментальное свойство NULL : при сравнении его с любым , включая NULL , он возвращает false , что является почему то, что вы делаете, не работает.

Итак, первый вопрос, на который нужно ответить: почему вы хотите, чтобы строка с NULL lastname возвращалась, когда они вводят lastname of "smith"? Возможно, вы имеете в виду, что либо имя , либо фамилия должны совпадать для возврата, и в этом случае вы выполняете неправильный запрос. Самое наивное решение:

SELECT firstname, lastname, ....
FROM profiles
WHERE IFNULL(firstName LIKE'%{firstname}%'
OR lastName LIKE '%{lastName}%'

Теперь это будет работать для нескольких сотен и, возможно, нескольких тысяч строк, но не будет масштабироваться дальше этого по нескольким причинам:

  1. OR обычно плохо с точки зрения производительности. По возможности избегайте их. Если вы посмотрите на приложения баз данных, написанные опытными программистами, вы, вероятно, не найдете ни одного условия OR (за исключением тех, кто пропагандирует достоинства OR на фоне того, что однажды написал приложение гостевой книги, у которого 3 пользователя и 2 обращения в месяц);
  2. Выполнение LIKE с % впереди будет означать, что никакие индексы не будут предъявлены иски.

Есть несколько решений (2). Вероятно, самым простым в MySQL является использование полнотекстового поиска в таблицах MyISAM. Он не найдет совпадений, таких как «Johannes», если вы введете «han», но обычно этого достаточно.

Часто вы имеете дело с условиями ИЛИ , используя либо UNION , либо (предпочтительно) UNION ALL в нескольких запросах.Например:

SELECT firstname, lastname, ....
FROM profiles
WHERE firstName LIKE'%{firstname}%'
AND lastName LIKE '%{lastName}%'
UNION ALL
SELECT firstname, lastname, ....
FROM profiles
WHERE firstName LIKE'%{firstname}%'
AND lastname IS NULL
UNION ALL
SELECT firstname, lastname, ....
FROM profiles
WHERE firstName IS NULL
AND lastName LIKE '%{lastName}%'
UNION ALL
SELECT firstname, lastname, ....
FROM profiles
WHERE firstName IS NULL
AND lastName IS NULL

Выглядит большим и некрасивым, но UNION ALL очень хорошо масштабируется (игнорируя % в начале критерия LIKE ). По сути, он объединяет (в данном случае) четыре запроса. UNION будет выполнять неявное DISTINCT в строках результатов, но мы знаем, что здесь не будет перекрытия, потому что мы меняем проверку на NULL .

Другая возможность - не рассматривать NULL как нечто, что вы хотите найти. Это гораздо лучшее и интуитивно понятное решение (имхо). Если кто-то набирает фамилию «Смит», вы действительно хотите, чтобы отображались строки с NULL фамилией?

Или вы хотите, чтобы они отображались, потому что у вас могло быть совпадение по первому имя? Если да, то вам нужен немного другой запрос. Например:

SELECT firstname, lastname, ....
FROM profiles
WHERE id IN (
  SELECT id 
  FROM profiles
  WHERE firstName LIKE'%{firstname}%'
  UNION ALL
  SELECT id 
  FROM profiles
  WHERE lastName LIKE '%{lastName}%'
)
2
ответ дан 17 December 2019 в 18:13
поделиться
Другие вопросы по тегам:

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