我需要将一个表加入到 select/group-by 查询(包括同一个表)中,我想使用 Arel 来完成。
我有一个表:phenotypes
其中是has_and_belongs_to_many :genes
,哪些是他们自己has_and_belongs_to_many :orthogroups
。因此,表型和邻位群之间的关系是多对多的。
我有两个范围(在正交组上),它们获取与特定表型相关的所有正交组:
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")
}
因此,doingOrthogroup.with_associated_gene_ids_for_phenotype(48291)
应该返回一个正交组 ID 表以及将它们与表型联系起来的基因。
那东西一切正常。
问题是我想获取其余部分orthogroups.*
并将其加入第二个范围的结果,因此基因列表基本上就像我的 Orthogroup ActiveRecord 模型上的一个额外字段。
大致是这样的:
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 在两个上下文中使用表“正交组”,这让我很担心;但是,对结果的抽查表明查询是正确的。
尽管如此,这并不是我所希望的优雅解决方案。没有尴尬就可以做到这一点"inner join (...)"
吗?