テーブルを select/group-by クエリ (同じテーブルを含む) に結合する必要があり、Arel を使用して実行したいと考えています。
私は自分自身である:phenotypes
which areの表を持っています。その結果、表現型とオルソグループの関係は多対多になります。has_and_belongs_to_many :genes
has_and_belongs_to_many :orthogroups
特定の表現型に関連付けられたすべてのオルソグループを取得する 2 つのスコープ (オルソグループ上) があります。
scope :with_phenotype, lambda { |phenotype_id|
where("observations.phenotype_id = ?", phenotype_id).
joins("inner join orthologies on (orthologies.orthogroup_id = orthogroups.id) inner join observations on (observations.gene_id = orthologies.gene_id)")
}
scope :with_associated_gene_ids_for_phenotype, lambda { |phenotype_id|
with_phenotype(phenotype_id).
select("orthogroups.id, array_agg(distinct observations.gene_id) as associated_gene_ids").
group("orthogroups.id")
}
したがって、実行Orthogroup.with_associated_gene_ids_for_phenotype(48291)
すると、オルトグループ ID と、それらを表現型にリンクする遺伝子のテーブルが返されます。
そのようなものはすべて正常に機能します。
orthogroups.*
問題は、遺伝子のリストが基本的に私の Orthogroup ActiveRecord モデルの追加フィールドのようになるように、残りを取得して 2 番目のスコープの結果に結合したいということです。
おおよそ、次のようなものです。
SELECT o1.*, o_genes.associated_gene_ids
FROM orthogroups o1
INNER JOIN (
SELECT o2.id, array_agg(DISTINCT obs.gene_id) AS associated_gene_ids
FROM orthogroups o2
INNER JOIN orthologies ortho ON (ortho.orthogroup_id = o2.id)
INNER JOIN observations obs ON (ortho.gene_id = obs.gene_id)
WHERE obs.phenotype_id = ? GROUP BY o2.id
) AS o_genes
ON (o1.id = o_genes.id);
これで、そのクエリが機能するように見えます。しかし、これらの遺伝子を取得するために、Orthogroup テーブルを独自のスコープに直接結合する方法を見つけたいと思っています。
SQL を使用する方が簡単かもしれませんが、Arel を使用すると簡単な方法があるはずです。同様の質問をいくつか見つけましたが、答えがあるようには見えません。
私が見つけた最も近い解決策はこれです:
def self.orthogroups phenotype_id
Orthogroup.select("orthogroups.*, o_genes.associated_gene_ids").
joins(Arel.sql("inner join (" + Orthogroup.with_associated_gene_ids_for_phenotype(phenotype_id).to_sql + ") AS o_genes ON (o_genes.id = orthogroups.id)"))
end
出力された SQL は、テーブル「orthogroups」を 2 つのコンテキストで使用しており、これが心配でした。ただし、結果のスポット チェックは、クエリが正しいことを示唆しています。
それでも、これは私が望んでいたエレガントなソリューションではありません。ぎこちなくこれを行うことは可能です"inner join (...)"
か?