sql >> データベース >  >> RDS >> Mysql

Railsで動的にクエリを構築する

    ハッシュに基づいてSQLクエリを作成できます。最も一般的なアプローチは生のSQLであり、ActiveRecordで実行できます。 。

    正しいアイデアを提供するためのコンセプトコードは次のとおりです。

    query_select = "select * from "
    query_where = ""
    tables = [] # for selecting from all tables
    hash.each do |table, values|
      table_name = table.constantize.table_name
      tables << table_name
      values.each do |q|
        query_where += " AND " unless query_string.empty?
        query_where += "'#{ActiveRecord::Base.connection.quote(table_name)}'."
        query_where += "'#{ActiveRecord::Base.connection.quote(q[fieldName)}'"
        if q[:operator] == "starts with" # this should be done with an appropriate method
          query_where += " LIKE '#{ActiveRecord::Base.connection.quote(q[val)}%'"
        end
      end
    end
    query_tables = tables.join(", ")
    raw_query = query_select + query_tables + " where " + query_where 
    result = ActiveRecord::Base.connection.execute(raw_query)
    result.to_h # not required, but raw results are probably easier to handle as a hash
    

    これは何をしますか:

    • query_select 結果に必要な情報を指定します
    • query_where すべての検索条件を作成し、入力をエスケープしてSQLインジェクションを防止します
    • query_tables 検索する必要があるすべてのテーブルのリストです
    • table_name = table.constantize.table_name モデルで使用されるSQLtable_nameが表示されます
    • raw_query 上記の部分からの実際の結合SQLクエリです
    • ActiveRecord::Base.connection.execute(raw_query) データベースでSQLを実行します

    SQLインジェクションを防ぐために、ユーザーが送信した入力はすべて引用符で囲み、適切にエスケープしてください。

    この例では、作成されたクエリは次のようになります。

    select * from companies, categories where 'companies'.'name' LIKE 'a%' AND 'companies'.'hq_city' = 'karachi' AND 'categories'.'name' NOT LIKE '%ECommerce%'
    

    このアプローチでは、関連するテーブルを結合するための追加のロジックが必要になる場合があります。あなたの場合、company およびcategory 関連付けがある場合は、このようなものをquery_whereに追加する必要があります

    "AND 'company'.'category_id' = 'categories'.'id'"
    

    簡単なアプローチ: クエリ可能なモデル/テーブルのすべてのペアに対してハッシュを作成し、そこに適切な結合条件を格納できます。このハッシュは、中規模のプロジェクトでも複雑すぎないようにする必要があります。

    ハードアプローチ: has_manyがある場合、これは自動的に実行できます 、has_one およびbelongs_to モデルで適切に定義されています。モデルの関連付けは、reflect_on_all_associations<を使用して取得できます。 / a> 。 Breath-First-Searchを実装する またはDepth-First Search アルゴリズムを実行し、任意のモデルから開始して、json入力から他のモデルとの一致する関連付けを検索します。 json入力から未訪問のモデルがなくなるまで、新しいBFS/DFSの実行を開始します。見つかった情報から、すべての結合条件を導き出し、それらをwhereの式として追加できます。 上で説明した生のSQLアプローチの節。さらに複雑ですが、データベースのschemaを読み取ることも実行可能です。 foreign keysを探すことにより、ここで定義されているのと同様のアプローチを使用します 。

    関連付けの使用: それらすべてがhas_manyに関連付けられている場合 / has_oneActiveRecordで結合を処理できます joinsを使用する injectを使用したメソッド このような「最も重要な」モデルについて:

    base_model = "Company".constantize
    assocations = [:categories]  # and so on
    result = assocations.inject(base_model) { |model, assoc| model.joins(assoc) }.where(query_where)
    

    これは何をしますか:

    • base_modelを開始入力としてに渡します。 Enumerable.inject 、input.send(:joins、:assoc)を繰り返し呼び出します(私の例では、これはCompany.send(:joins, :categories)を実行します これは`Company.categories
    • と同等です
    • 結合された結合では、where条件(上記のように構築された)を実行します

    免責事項 必要な正確な構文は、使用するSQL実装によって異なる場合があります。



    1. OracleデータベースでRAISE_APPLICATION_ERRORメソッドを使用してユーザー定義の例外を宣言する

    2. ORDERBYとLIMITを使用したUPDATEがMYSQLで機能しない

    3. 演算子と>=AND <=の間に:パフォーマンスの違いはありますか?

    4. 任意の列に「x」が含まれるSQLServerSELECT