ruby-on-rails-3.2 - 如何通过多个 has_many 关联求和?

标签 ruby-on-rails-3.2 sum has-many

我确实有这样的嵌套关联:

# note : irregular inflection (proj_paquet_mesures : proj_paquets_mesures)
class ProjPaquetMesures < ActiveRecord::Base
  ...
  has_many :proj_mesures
end

class ProjMesure < ActiveRecord::Base
  ...
  has_many :proj_projets
end

class Projprojet < ActiveRecord::Base
  ...
  has_many :proj_sous_projets
end

class ProjSousProjet < ActiveRecord::Base
  ...
  has_many :proj_charges
end

class ProjCharge < ActiveRecord::Base
  # integer value
  attr_accessible :montant 
end

我想将所有“montant”的总和嵌套到我的 proj_paquet_mesures 之一中。

我执行了以下不起作用的操作(尽管使用“includes”,但对 SQL 查询效率不高):

proj_paquet_mesures = ProjPaquetMesures.includes([{:proj_mesures => {:proj_projets => {:proj_sous_projets => :proj_charges}}}]).find(1)
total_charges_of_my_paquet_mesures = proj_paquet_mesures.proj_mesures.proj_projets.proj_sous_projets.proj_charges.sum(:montant)

第一行代码产生 4 个查询,而不是预期的一个连接查询:

  ProjPaquetMesures Load (8.9ms)  SELECT "proj_paquets_mesures".* FROM "proj_paquets_mesures" WHERE "proj_paquets_mesures"."id" = $1 LIMIT 1  [["id", 1]]
  ProjMesure Load (1.4ms)  SELECT "proj_mesures".* FROM "proj_mesures" WHERE "proj_mesures"."proj_paquet_mesures_id" IN (1)
  ProjProjet Load (0.6ms)  SELECT "proj_projets".* FROM "proj_projets" WHERE "proj_projets"."proj_mesure_id" IN (3)
  ProjSousProjet Load (0.8ms)  SELECT "proj_sous_projets".* FROM "proj_sous_projets" WHERE "proj_sous_projets"."proj_projet_id" IN (1)
  ProjCharge Load (2.7ms)  SELECT "proj_charges".* FROM "proj_charges" WHERE "proj_charges"."proj_sous_projet_id" IN (2)

第二行代码根本不起作用。

有什么想法吗?

===更新===

根据第一个答案,似乎 PostgreSQL 比 MySQL 更符合 SQL 标准,因此它需要为您想要的每个选定列使用“GROUP BY”子句与您的聚合函数一起显示。所以我尝试了以下代码:

proj_paquet_mesures = ProjPaquetMesures.joins([{:proj_mesures => {:proj_projets => {:proj_sous_projets => :proj_charges}}}]).select("proj_charges.id, sum(proj_charges.montant) as total_montant").group([id]).find(1)

但 Rails 回复 NameError: undefined local variable or methodid' for main:Object`

official doc不清楚在哪里应用分组方法,并且缺乏解释和示例。

所以我删除了 proj_charges.id 并最终得到这个:

proj_paquet_mesures = ProjPaquetMesures.joins([{:proj_mesures => {:proj_projets => {:proj_sous_projets => :proj_charges}}}]).select("sum(proj_charges.montant) as total_montant").find(1)
total_charges_of_my_paquet_mesures = proj_paquet_mesures.total_montant

它可以工作,但如果有一天我想计算每个 proj_charges.id 的总计,那么这是行不通的。

更多由这 4 级嵌套连接生成的查询计划表明,Rails 还不够成熟,无法管理专业的复杂数据库

当您开始使用“JOIN”sql 命令时,您需要能够告诉数据库您希望她以什么顺序加入表。否则,如果您不这样做并使用深度嵌套的 JOIN,您将面临数据库的响应问题。

为此,您需要能够在 JOIN 指令之间使用括号来指示数据库必须按照哪个顺序连接哪些表。 Rails 还无法让您做到这一点。

相反,您必须使用 Rails find_by_sql 方法来依赖 SQL。

ProjSouProjet.find_by_sql ['SELECT sp.id AS "proj_sous_projet_id", SUM(c.montant) AS total FROM proj_charges c JOIN (proj_sous_projets sp JOIN (proj_projets p JOIN (proj_mesures m JOIN proj_paquets_mesures pm ON m.proj_paquet_mesures_id = pm.id AND pm.id = ?) ON p.proj_mesure_id = m.id) ON sp.proj_projet_id = p.id) ON c.proj_sous_projet_id = sp.id GROUP BY sp.id', 1]

更多说明here浅谈PostgreSQL的Join和查询规划。

最佳答案

这应该有效。单一查询。

 proj_paquet_mesures = ProjPaquetMesures.join([{:proj_mesures => {:proj_projets => {:proj_sous_projets => :proj_charges}}}]).select("proj_charges.*, sum(proj_charges.monatent) as total_monatant)").find()
 proj_paquet_mesures.total_monatent

关于ruby-on-rails-3.2 - 如何通过多个 has_many 关联求和?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15270642/

相关文章:

R:自动计算秩和

java - 是否可以在不装箱/拆箱的情况下添加包装数字?

ruby-on-rails - 如何使用 Ember Data & Rails 在单个 Ember.js 表单中保持 hasMany 关联?

ruby-on-rails - 成功提交 AJAX 表单后如何重定向 (Rails 3.2)

ruby-on-rails - 在 url 路由中允许用户名中有空格

google-sheets - 计算谷歌电子表格中项目总和的公式

ruby-on-rails - Rails4 has_many 通过带参数

ruby-on-rails - Rails has_one 每个作用域

ruby-on-rails - 让 fields_for 与 has_many 关系一起工作

error-handling - 翻译自定义错误消息