2016-05-03 11 views
2

私は、作る、私はRubyでそうのようなデータを受信して​​いMySQLの声明

の下に投稿されたすべての条件を満たしているプロファイルのセットを返すクエリを生成しています内容に基づいて動的なMySQLのクエリ -

[{ attribute_id: 58, parent_profile_name: 'Douglas-Connelly' }, 
{ attribute_id: 26, parent_profile_name: 'Brekke LLC' }, 
{ attribute_id: 35, val: 'Asa' }, 
{ attribute_id: 38, val: 'Stanton' }] 

これらは私がすべてのプロファイルを返却する必要があるデータベース

profile_attribute_values 
profile_id attribute_id parent_profile_id val 
6   58    2 
6   26    5 
6   35    nil     'Asa' 
6   38    nil     'Stanton' 

profile 
id  name 
2  Douglas-Connelly 
5  Brekke LLC 
6  nil 

の現在の内容ですWHAT I attribute_idはXであり、valはyはprofile_attribute_valuesとの関係を、持っているプロファイル、AND attribute_idはXであり、parent_profile名= Y

- それは、すべての条件を満たしていますCURRENTLY

SELECT * FROM 

(SELECT P2. * 
FROM profile_attribute_values PAV 
INNER JOIN profiles P1 ON P1.id = PAV.parent_profile_id 
INNER JOIN profiles P2 ON P2.id = PAV.profile_id 
WHERE (PAV.ne_attribute_id = '58' AND P1.`name` = 'Douglas-Connelly') 
) A, 

(SELECT P1. * 
FROM profiles P1 
INNER JOIN profile_attribute_values PAV ON P1.id = PAV.profile_id 
INNER JOIN profile_attribute_values PAV2 ON P1.id = PAV2.profile_id 
WHERE (PAV.ne_attribute_id = '35' AND PAV.val = 'ASA') 
AND (PAV2.ne_attribute_id = '38' AND PAV2.val = 'Stanton') 
) B 

WHERE A.id = B.id 

を持っているこれは私がワンまさにある

profile 
id name 
6  nil 

を返します。 tは、トリッキーな部分が第二parent_profile Iが26をATTRIBUTE_ID必要条件、およびparent_profile_nameですが: 'Brekke LLC'

私はこの文句を言わない仕事を知っているが、私はこの

SELECT * FROM 

(SELECT P2. * 
FROM profile_attribute_values PAV 
INNER JOIN profiles P1 ON P1.id = PAV.parent_profile_id 
INNER JOIN profiles P2 ON P2.id = PAV.profile_id 
WHERE (PAV.ne_attribute_id = '58' AND P1.`name` = 'Douglas-Connelly') 
AND (PAV.ne_attribute_id = '26' AND P1.`name` = 'Brekke LLC') 
) A, 
..... 

ような何かをするためにこれを必要とします私は動的にSQL文を生成しているので、できるだけきれいにする必要があります。私は一般的にすべてのためにルビーのアクティブなレコードを使用するので、私は少しは、それはSQL文になると思います。ありがとう!

UPDATE

わかりました私は、私は必要な動的なクエリを生成するための最適なソリューションを見つけたデータベースへの単一の呼び出しを行います。これは完成したクラスです

class ProfileSearch 
    def initialize(params, args = {}) 
    @attr_vals = params 
    @options = args 
    filter_attrs 
    end 

    attr_accessor :parent_attrs, :string_attrs 

    def search 
    Profile.joins(generate_query) 
    end 

    def generate_query 
    q = '' 
    q << parents_query 
    q << attr_vals_query 
    end 

    def parents_query 
    str = '' 
    parent_attrs.each_with_index do |pa, i| 
     str << "INNER JOIN profile_attribute_values PAVP#{i} ON profiles.id = PAVP#{i}.profile_id "\ 
       "AND PAVP#{i}.ne_attribute_id = #{pa} "\ 
       "INNER JOIN profiles PP#{i} ON PP#{i}.id = PAVP#{i}.parent_profile_id "\ 
       "AND PP#{i}.`name` = '#{@attr_vals[pa.to_s]}' " 
    end 
    str 
    end 

    def attr_vals_query 
    str = '' 
    string_attrs.each_with_index do |a, i| 
     str << "INNER JOIN profile_attribute_values PAVS#{i} ON profiles.id = PAVS#{i}.profile_id "\ 
      "AND PAVS#{i}.ne_attribute_id = #{a} AND PAVS#{i}.val = '#{@attr_vals[a.to_s]}' " 
    end 
    str 
    end 

    def filter_attrs 
    ne = NeAttribute.find(@attr_vals.keys) 
    self.parent_attrs = ne.select{ |x| x.parent_profile)_attr? }.map(&:id) 
    self.string_attrs = ne.select{ |x| x.string_attr? }.map(&:id) 
    end 
end 

答えて

1

最初に知る必要があるのはjoinsです。

ので、同じようにそれを使用します。

relation_1 = ProfileAttributeValue.joins(" 
    INNER JOIN profiles P1 ON P1.id = PAV.parent_profile_id 
    INNER JOIN profiles P2 ON P2.id = PAV.profile_id 
").where(..).pluck(:id) 

relation_2 = ProfileAttributeValue.joins...where...pluck(:id) 

relation_1とrelation_2はまだ実行されていません。それらはActiveRecord関係です。

私は、次のトリック好き:

ProfileAttributeValue.where(["profile_attribute_values.id in (?) or profile_attribute_values.id in (?)]", relation_1, relation_2) 

繰り返しますが、それは単にActiveRecordの関係ですが。好奇心が強い場合はto_sqlに電話してください。 .whereなどを追加してください。実行すると、DB上で1つのクエリになります。

+0

良いの呼び出しを生成するクラスですこれは、プロファイルテーブルの別のインスタンスでの自己結合によるものです。私は本当にこれがたくさん呼ばれているので、できるだけ最適化されている必要があります。私は実際に把握しましたが、上記の更新を参照してください。 –

1

誰かがそれを逃した場合のために、私が答えとして行ったことを投稿する。これは本質的に私が必要な正確なデータを引き出すことを可能にする単一の結合クエリを作成します。生成されたクエリは次のようになります -

SELECT `profiles`.* 
FROM `profiles` 
INNER JOIN profile_attribute_values PAVP0 ON profiles.id = PAVP0.profile_id 
    AND PAVP0.ne_attribute_id = 26 
INNER JOIN profiles PP0 ON PP0.id = PAVP0.parent_profile_id 
    AND PP0.`name` = 'Brekke LLC' 
INNER JOIN profile_attribute_values PAVP1 ON profiles.id = PAVP1.profile_id 
    AND PAVP1.ne_attribute_id = 58 
INNER JOIN profiles PP1 ON PP1.id = PAVP1.parent_profile_id 
    AND PP1.`name` = 'Douglas-Connelly' 
INNER JOIN profile_attribute_values PAVS0 ON profiles.id = PAVS0.profile_id 
    AND PAVS0.ne_attribute_id = 35 AND PAVS0.val = 'Asa' 
INNER JOIN profile_attribute_values PAVS1 ON profiles.id = PAVS1.profile_id 
    AND PAVS1.ne_attribute_id = 38 AND PAVS1.val = 'Stanton' 

これはこれはまだ複数のクエリを作成し、その私が必要とする正確に何を取得していないが、方法を結合上の

class ProfileSearch 
    def initialize(params, args = {}) 
    @attr_vals = params 
    @options = args 
    filter_attrs 
    end 

    attr_accessor :parent_attrs, :string_attrs 

    def search 
    Profile.joins(generate_query) 
    end 

    def generate_query 
    q = '' 
    q << parents_query 
    q << attr_vals_query 
    end 

    def parents_query 
    str = '' 
    parent_attrs.each_with_index do |pa, i| 
     str << "INNER JOIN profile_attribute_values PAVP#{i} ON profiles.id = PAVP#{i}.profile_id "\ 
       "AND PAVP#{i}.ne_attribute_id = #{pa} "\ 
       "INNER JOIN profiles PP#{i} ON PP#{i}.id = PAVP#{i}.parent_profile_id "\ 
       "AND PP#{i}.`name` = '#{@attr_vals[pa.to_s]}' " 
    end 
    str 
    end 

    def attr_vals_query 
    str = '' 
    string_attrs.each_with_index do |a, i| 
     str << "INNER JOIN profile_attribute_values PAVS#{i} ON profiles.id = PAVS#{i}.profile_id "\ 
      "AND PAVS#{i}.ne_attribute_id = #{a} AND PAVS#{i}.val = '#{@attr_vals[a.to_s]}' " 
    end 
    str 
    end 

    def filter_attrs 
    ne = NeAttribute.find(@attr_vals.keys) 
    self.parent_attrs = ne.select{ |x| x.parent_profile)_attr? }.map(&:id) 
    self.string_attrs = ne.select{ |x| x.string_attr? }.map(&:id) 
    end 
end