Общее решение Ruby для SQLite3 «LIKE» или PostgreSQL «ИЛИКЕ»?

Я использую SQLite3 для разработки и PostgreSQL для развертывания. Однако я столкнулся со следующей проблемой:

Мой простой поиск с использованием SQLite3 :

 def self.search(search) if search find(:all, :conditions => ["style LIKE ? OR construction LIKE ?", "%#{search}%", "%#{search}%"]) else find(:all) end end 

Однако для PostgreSQL это не работает, и мне нужно заменить LIKE для ILIKE для решения проблемы:

 def self.search(search) if search find(:all, :conditions => ["style ILIKE ? OR construction ILIKE ?", "%#{search}%", "%#{search}%"]) else find(:all) end end 

Есть ли способ «Ruby» для этих поисков в любой базе данных?

EDIT – основываясь на ваших ответах, я не верю, что найду для вас общее решение Ruby.

Я последовал за Ruby on Rails Tutorial: Learn Rails по примеру – Michael Hartl , где последний Gemfile показывает обе базы данных … ну, неутешительно …

7 Solutions collect form web for “Общее решение Ruby для SQLite3 «LIKE» или PostgreSQL «ИЛИКЕ»?”

Здесь лежит корень проблемы :

Я использую SQLite3 для разработки и PostgreSQL для развертывания.

Это плохая идея. Вы будете продолжать сталкиваться с несовместимостями – или хуже: не осознавать их до тех пор, пока не будет нанесен ущерб.
Используйте ту же СУБД (PostgreSQL) для разработки и производства и избавьте себя от бессмысленной проблемы.


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

 lower(style) LIKE lower(?) 

Работает на обеих платформах.

  • Вы можете сбросить правую lower() , если вы предоставите шаблон поиска в нижнем регистре.

  • В стандартном SQLite lower(X) только сбрасываются буквы ASCII. Более того, я цитирую главу « Основные функции» в руководстве SQLite :

    Нижняя (X) функция возвращает копию строки X со всеми символами ASCII, преобразованными в нижний регистр. Встроенная функция lower () по умолчанию работает только для символов ASCII. Чтобы преобразовать случайные символы без символов ASCII, загрузите расширение ICU .

    Акцент мой.

  • PostgreSQL lower(X) работает с UTF-8 из коробки.


В качестве приветственного побочного эффекта вы можете ускорить этот запрос в PostgreSQL с индексом выражения lower(style) , который будет быстрее, чем использование ILIKE и базового индекса по style .

Кроме того, поскольку PostgreSQL 9.1 вы можете использовать индекс GIN или GIST с расширением pg_trgm для ускорения любых запросов LIKE и ILIKE – триграммы нечувствительны к регистру. Подробные инструкции и ссылки в этом связанном ответе:

  • Аналогичные строки UTF-8 для поля автозаполнения

Я думаю, что Arel – лучший способ решить эту проблему. Он используется Rails для активной записи и независим от базы данных. Ваш код будет работать одинаково в sqlite3 или postgres, который, по-видимому, соответствует вашей ситуации. Использование метода совпадений автоматически переключится на ilike в среде postgres. пример:

 users=User.arel_table User.where(users[:style].matches("%#{search}%").or(users[:construction].matches("%#{search}%"))) 

Вы можете получить дополнительную информацию от github: https://github.com/rails/arel/

Нет, нет rubyового пути для поиска базы данных. Ruby on Rails (в частности, ActiveRecord ) содержит вспомогательные методы для выполнения операций CRUD на RDB, поддерживаемых ActiveRecord, но нет лучшего способа поиска с использованием LIKE, а затем примеров вы предоставили.

Раздел документа Rails, связанный с этим обсуждением, будет ActiveRecord :: FinderMethods .

Как побочная заметка, вместо того, чтобы делать find(:all) вы можете просто сделать все .

В документах Rails используется тот же синтаксис, что и использование для выполнения инструкций LIKE, то есть:

 Person.exists?(['name LIKE ?', "%#{query}%"]) 

Использование вышеописанного метода совершенно безопасно.

Причина, по которой такие утверждения, подобные приведенным ниже, небезопасны, заключается в том, что строка where передается непосредственно в запрос базы данных без какой-либо дезинфекции, что оставляет вашу базу данных открытой для использования (т. Е. Простой апостроф в params[:first_name] может испортить весь ваш запрос и оставьте уязвимость вашей базы данных – в частности, SQL-инъекцией). В приведенном выше примере ActiveRecord может дезинфицировать параметры, которые вы передаете в запрос.

 Client.where("first_name LIKE '%#{params[:first_name]}%'") 

К сожалению, я не думаю, что вы найдете хорошее решение. Единственный другой синтаксис, ansible вам, а не: условия, заключается в использовании предложения .where:

 where(["style ILIKE ? OR construction ILIKE ?", "%#{search}%", "%#{search}%"]) 

К сожалению, как вы, вероятно, поняли, этот альтернативный синтаксис столкнется с одной и той же проблемой. Это всего лишь одно из неприятностей, с которыми вы столкнетесь, имея существенно отличающуюся среду разработки от вашей производственной среды – есть и другие довольно существенные различия между SQLite и PostgresSQL. Я бы рекомендовал просто установить Postgres на вашу машину разработки и использовать это. Это упростит процесс разработки и сделает ваш код намного чище.

Хотя squeel использовать разные базы данных в области производства и разработки, все же неплохо использовать камень squeel : https://github.com/ernie/squeel/

С его помощью вы можете написать свои запросы с помощью DSL, что легко и, возможно, намного чище и удобочитаемо, чем raw sql, и этот камень будет обрабатывать его перевод на SQL, специфичный для используемой RDBMS.

У Райана Бэйтса есть хорошее видео об этом: http://railscasts.com/episodes/354-squeel

Однажды я столкнулся с одной проблемой: вот мое решение:

Я написал небольшую библиотеку, которая позволяет использовать функцию для каждой базы данных:

 class AdapterSpecific class < < self def like_case_insensitive case ActiveRecord::Base.connection.adapter_name when 'PostgreSQL' 'ILIKE' else 'LIKE' end end def random #something end end 

Чтобы использовать его в своей модели:

 def self.search(search) if search find(:all, :conditions => ["style #{AdapterSpecific.like_case_insensitive} :query OR construction #{AdapterSpecific.like_case_insensitive} :query", {:query => "%#{search}%"}]) else find(:all) end end 

С момента написания, я перенес базу данных развертывания в Postgres, поскольку это намного лучше настроить по нескольким причинам (см. Другие ответы).

Вы также можете использовать полнотекстовый поиск Postgres, который сделает ваш текстовый поиск более эффективным, см. Текст для базовой реализации или pg_search, если вам нужно больше настроек.

Поиск с использованием LIKE может быть болезненным в базе данных. Конечно, он не будет использовать индекс, который может быть довольно дорогостоящим.

Более длинный ответ: я бы рекомендовал использовать Postgres в разработке (ditching sqlite3), а затем иметь полнотекстовый индекс во всех style, construction ваших поисковых полей style, construction tsvector тип tsvector Postgres.

Полнотекстовый поиск в Postgres при использовании индекса очень быстрый.

  • Неопределенная эталонная ошибка для метода шаблона
  • Почему аргумент шаблона не может быть выведен, если он используется в качестве параметра шаблона для другого шаблона?
  • Вложенные шаблоны с зависимой областью
  • Поиск имен в шаблонах C ++
  • Можно ли использовать Razor View Engine вне asp.net
  • Использовать композицию над наследованием
  • Строки C-Style в качестве аргументов шаблона?
  • Каковы некоторые параметры шаблона шаблона?
  • c ++ шаблонная функция частичной специализации
  • Почему бы не вывести параметр шаблона из конструктора?
  • Может кто-нибудь объяснить этот код шаблона, который дает мне размер массива?
  • Interesting Posts

    Как я могу предотвратить копирование файлов в моем USB-накопителе?

    Почему индикатор жесткого диска мигает один раз в секунду?

    Элемент прокрутки в виде с seleniumом

    Java OutOfMemoryError странное поведение

    Сравнить контрольную сумму с Fdupes только для папок с определенным именем?

    Как запустить интегрированный видеоадаптер вместе с графическим процессором в системе Ivy Bridge?

    Можете ли вы подключить батарею, когда ноутбук включен только в сети?

    Подключение нескольких точек доступа

    Можно ли клонировать и загружать жесткий диск моего ноутбука на другой ноутбук?

    Apple Mail не применяет правила, если я не выберу «Применить правила» вручную

    Снимок экрана для карт Google, которые необходимо прокрутить

    Добавление закладок в Microsoft Edge вручную

    Cloned Linux не распознает пространство нового флеш-накопителя?

    Получить controller и имя действия из controllerа?

    Почему этот шаблон совпадения недоступен при использовании нелитеральных шаблонов?

    Давайте будем гением компьютера.