0

次の表現があります。

  result = where(
    Sequel.like(Sequel.function(:lower, Sequel.join([:first_name, :last_name], ' ')), "%#{query.name.downcase}%") |
      Sequel.like(Sequel.function(:lower, :email), "%#{query.name.downcase}%")
  )

複数の列に対して同じような式を実行するように、sequel に指示できる方法はありますか?

4

2 に答える 2

0

これが私がすることです:

まず、検索用のメール アドレスやユーザー名フィールドなどのデータは、データベース内で小文字に正規化する必要があります。これにより、コーディングが大幅に簡素化されます。

ユーザーの姓名を表示する場合など、元の大文字と小文字を区別する必要がある場合は、それらを別個の姓名フィールドとして保持し、検索用に既に結合およびハッシュされている別のフィールドを作成し、そのフィールドを見ると、コード内の同じハッシュ。それがインデックス化されている場合、検索を使用する場合と比較して、like検索が非常に高速になります。

whereSQL パーシャルを生成してクエリに挿入するのではなく、純粋な Sequel を使用してプログラムで生成するコードを次に示します。Sequel は SQLite の構文を認識しており、動作する where 句を自動的に作成することに注意してください。PostgreSQL、MySQL、Oracle、MSSQL、Sybase、または Sequel がサポートするその他の DBM に接続している場合も同様です。コードを機能させるためだけにコードを微調整する必要はありません。使用するドライバーと DB 資格情報を Sequel に伝える DSN を調整するだけです。

テスト DB の構築:

require 'sequel'

DB = Sequel.sqlite
DB.create_table :items do
  primary_key :id
  String :first_name
  String :last_name
  String :email
  String :attr1, :default => 'attr'
  String :attr2, :default => 'attr'
end

items = DB[:items]
%w[Jane Jim John Junior].each do |fn|
  items.insert(:first_name => fn, :last_name => 'Doe', :email => fn.downcase + 'doe@email.com')
end
puts items.all

さあ、いくぞ...:

user_name = '%' + 'John Doe'.downcase + '%'
query = DB[:items].where(
  Sequel.ilike(
    Sequel.join([:first_name, :last_name], ' '),
    user_name
  )
)

columns = [:email, :attr1, :attr2]
columns.each do |col|
  query = query.or(
    Sequel.ilike(
      col,
      user_name.delete(' ')
    )
  )
end

puts query.sql

puts query.first

コードを実行すると、テーブルの内容が出力されます。

{:id=>1, :first_name=>"Jane", :last_name=>"Doe", :email=>"janedoe@email.com", :attr1=>"attr", :attr2=>"attr"}
{:id=>2, :first_name=>"Jim", :last_name=>"Doe", :email=>"jimdoe@email.com", :attr1=>"attr", :attr2=>"attr"}
{:id=>3, :first_name=>"John", :last_name=>"Doe", :email=>"johndoe@email.com", :attr1=>"attr", :attr2=>"attr"}
{:id=>4, :first_name=>"Junior", :last_name=>"Doe", :email=>"juniordoe@email.com", :attr1=>"attr", :attr2=>"attr"}

DB を照会するために生成された SQL:

SELECT * FROM `items` WHERE ((UPPER((`first_name` || ' ' || `last_name`)) LIKE UPPER('%john doe%') ESCAPE '\') OR (UPPER(`email`) LIKE UPPER('%johndoe%') ESCAPE '\') OR (UPPER(`attr1`) LIKE UPPER('%johndoe%') ESCAPE '\') OR (UPPER(`attr2`) LIKE UPPER('%johndoe%') ESCAPE '\'))

読みやすくするための書式設定:

SELECT * FROM `items`
WHERE (
  (UPPER((`first_name` || ' ' || `last_name`)) LIKE UPPER('%john doe%') ESCAPE '\') OR
  (UPPER(`email`) LIKE UPPER('%johndoe%') ESCAPE '\') OR
  (UPPER(`attr1`) LIKE UPPER('%johndoe%') ESCAPE '\') OR
  (UPPER(`attr2`) LIKE UPPER('%johndoe%') ESCAPE '\')
)

そして、クエリの後の結果の行:

{:id=>3, :first_name=>"John", :last_name=>"Doe", :email=>"johndoe@email.com", :attr1=>"attr", :attr2=>"attr"}

これは最も DRY なコードではありませんが、例としては要点を捉えています。

于 2013-07-30T15:44:46.867 に答える
0

次のようなものを使用できます

columns.map{|c| "c LIKE '%<someVar>%'}.join("AND ")

これにより、必要なすべての列の LIKE AND リストが作成されます。例えば

columns = ["age", "gender", "hair_colour"]
columns.map{|c| "c LIKE '%<someVar>%'}.join("AND ")

#=> age LIKE '%<someVar%' AND gender LIKE '%<someVar>%' AND hair_colour LIKE '%<someVar>%'

どのように入力するかは、コードの残りの部分がどのように構成されているかによって異なりますが、それはそれに適したフレームです。

別の方法として、同様の配列マッピング方法を使用することもできますが、マップ内で where() を使用します。遅延呼び出しにより、クエリを実行する前に任意の基準を反復処理できます。これにより、@the Tin Man が言及した潜在的な苦情が解決されます

于 2013-07-30T12:51:34.910 に答える