Нужен шаблон для динамического поиска нескольких таблиц SQL
Я ищу шаблон для выполнения динамического поиска по нескольким таблицам.
У меня нет контроля над устаревшей (и плохо спроектированной) структурой таблиц базы данных.
Рассмотрим сценарий, подобный поиску резюме, где пользователь может захотеть выполнить поиск по любым данным в резюме и получить список резюме, которые соответствуют его критериям поиска. Любое поле можно искать в любое время и в сочетании с одним или несколькими другими полями.
Фактический SQL-запрос создается динамически в зависимости от того, какие поля ищутся. Большинство решений, которые я нашел, включают сложные блоки if, но я не могу не думать, что должно быть более элегантное решение, поскольку это должно быть решенной проблемой к настоящему времени.
Да, так что я пошел по пути динамического построения SQL в коде. Кажется чудовищным. Если я действительно попытаюсь поддержать запрашиваемую способность запрашивать любую комбинацию любого поля в любой таблице, это будет один МАССИВНЫЙ набор операторов if. дрожать
Я считаю, что я прочитал, что COALESCE работает, только если ваши данные не содержат NULL. Это верно? Если это так, не надо, так как у меня есть NULL значения повсюду.
3 ответа
Насколько я понимаю (и я также пишу против ужасной устаревшей базы данных), не существует такого понятия, как динамические предложения WHERE. Это НЕ было решено.
Лично я предпочитаю генерировать динамические поиски в коде. Делает тестирование удобным. Обратите внимание: когда вы создаете SQL-запросы в коде, не объединяйте их при вводе данных пользователем. Используйте свои @variables!
Единственная альтернатива - использовать оператор COALESCE. Допустим, у вас есть следующая таблица:
Users
-----------
Name nvarchar(20)
Nickname nvarchar(10)
и вы хотите искать имя или псевдоним. Следующий запрос сделает это:
SELECT Name, Nickname
FROM Users
WHERE
Name = COALESCE(@name, Name) AND
Nickname = COALESCE(@nick, Nickname)
Если вы не хотите что-то искать, просто введите ноль. Например, передача "brian" для @name и null для @nick приводит к оценке следующего запроса:
SELECT Name, Nickname
FROM Users
WHERE
Name = 'brian' AND
Nickname = Nickname
Оператор coalesce превращает нуль в оценку идентичности, которая всегда верна и не влияет на предложение where.
Что вам нужно, это что-то вроде SphinxSearch (для MySQL) или Apache Lucene.
Как вы сказали в своем примере, давайте представим резюме, которое будет состоять из нескольких полей:
- Элемент списка
- Название,
- Adreess,
- Образование (это может быть стол самостоятельно) или
- Опыт работы (это может вырасти до собственной таблицы, где каждая строка представляет предыдущую работу)
Таким образом, поиск слова во всех этих полях с помощью WHERE быстро становится очень длинным запросом с несколькими JOINS.
Вместо этого вы можете изменить свою структуру ссылок и думать о целом резюме как о том, что это единый документ, и вы просто хотите найти указанный документ.
Это то место, где работают такие инструменты, как Sphinx Search. Они создают индекс FULL TEXT для вашего "документа", а затем вы можете запросить sphinx, и он вернет вас назад, где в базе данных была найдена эта запись.
Действительно хорошие результаты поиска.
Не беспокойтесь о том, что эти инструменты не являются частью вашей СУБД, это избавит вас от головной боли при использовании подходящей модели "Документы" по сравнению с неверной "ТАБЛИЦЫ" для этого приложения.
Поиск и нормализация могут противоречить друг другу. Поэтому, вероятно, первым делом нужно получить некое "представление", которое показывает все поля, которые можно искать в виде одной строки с одним ключом, чтобы получить резюме. затем вы можете бросить что-то вроде Lucene перед этим, чтобы дать вам полнотекстовый индекс этих строк, способ, которым работает, вы спрашиваете его для "х" в этом представлении, и он возвращает вам ключ. Это отличное решение, рекомендованное Джоэлом на подкасте в течение первых двух месяцев IIRC.