Как бы я присоединился к подселекту (области), используя Rails 3 и Arel? - PullRequest
2 голосов
/ 24 декабря 2010

Мне нужно присоединить таблицу к запросу выбора / группировки (который включает в себя ту же таблицу), и я хотел бы сделать это с помощью 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")
  }

Таким образом, выполнение Orthogroup.with_associated_gene_ids_for_phenotype(48291) должно вернуть таблицу идентификаторов ортогрупп и генов, которые связывают их с фенотипами.

Все это прекрасно работает.

Проблема в том, что я хотел быполучите остаток 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, но кажется, что должен быть простой способс Арелем.Я нашел несколько похожих вопросов, но ни один из них, похоже, не дал ответов.

Наиболее близким решением, которое я нашел, является следующее:

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" вдва контекста, и это беспокоило меня;однако выборочная проверка результатов показывает, что запрос правильный.

Тем не менее, это не элегантное решение, на которое я мог бы надеяться.Возможно ли сделать это без неловких "inner join (...)"?

1 Ответ

0 голосов
/ 03 января 2011

Просто с первого взгляда на ваш код: пытались ли вы переименовать метод и локальную переменную "orthogroups" во что-то другое, поскольку у вас есть отношения с тем же именем?

...