Я гнездились ассоциации, как это:Как суммировать через несколько ассоциаций 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.
я выполняю следующее, который не работает (и не является эффективным для запросов 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-х запросов вместо signle ожидается один присоединиться запрос:
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)
Вторая строка кода не работает вообще.
Любая идея?
=== UPDATE ===
После первого ответа, оказывается, что PostgreSQL более уступчив к SQL стандарта, чем MySQL поэтому нуждается в «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 method
ид»для основной: 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 еще не в состоянии позволить вам сделать это.
Вместо этого вам нужно полагаться на SQL с помощью метода rails find_by_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.
Я удалил некоторые опечатки и скобки: proj_paquet_mesures = ProjPaquetMesures.joins ([{: proj_mesures => {: proj_projets => {: proj_sous_projets =>: proj_charges}}}]). select ("proj_charges. *, sum (proj_charges.montant) как total_montant"). find (1). Но у меня все еще есть ошибка PG: PG :: Ошибка: ERROR: столбец «proj_charges.id» должен появиться в предложении GROUP BY или использоваться в агрегированной функции LINE 1: SELECT proj_charges. *, Sum (proj_charges.montant) как total_m ... – Douglas