2014-11-04 102 views
0

我想弄清楚如何使用AR給出下面的模型定義複製下面的SQL查詢。演員是執行平均的必要條件。結果集應該按照foo分組(來自多態關聯)。任何幫助表示讚賞。Rails ActiveRecord查詢使用多個連接涉及多態關聯

SQL:

SELECT AVG(CAST(r.foo AS decimal)) "Average", s.bar 
FROM rotation r INNER JOIN cogs c ON r.cog_id = c.id 
      INNER JOIN sprockets s ON s.id = c.crankable_id 
      INNER JOIN machinists m ON r.machinist_id = m.id 
WHERE c.crankable_type = 'Sprocket' AND 
     r.machine_id = 123 AND 
     m.shop_id = 1 
GROUP BY s.bar 

ActiveRecord的模式:

class Rotation < ActiveRecord::Base 
    belongs_to :cog 
    belongs_to :machinist 
    belongs_to :machine 
end 

class Cog < ActiveRecord::Base 
    belongs_to :crankable, :polymorphic => true 
    has_many :rotation 
end 

class Sprocket < ActiveRecord::Base 
    has_many :cogs, :as => :crankable 
end 

class Machinist < ActiveRecord::Base 
    belongs_to :shop 
end 

UPDATE

,我想出了一個辦法,使其工作,但感覺像作弊。有沒有比這更好的方法?

Sprocket.joins('INNER JOIN cogs c ON c.crankable_id = sprockets.id', 
       'INNER JOIN rotations r ON r.cog_id = c.id', 
       'INNER JOIN machinists m ON r.machinist_id = m.id') 
    .select('sprockets.bar', 'r.foo') 
    .where(:r => {:machine_id => 123}, :m => {:shop_id => 1}) 
    .group('sprockets.bar') 
    .average('CAST(r.foo AS decimal)') 

SOLUTION

阿爾賓的回答沒有工作的,是的,但也使我工作的解決方案。首先,我在Cog中錯字,不得不從關係改變:

has_many :rotation 

以複數形式:

has_many :rotations 

隨着到位,我可以使用下面的查詢

Sprocket.joins(cogs: {rotations: :machinist}) 
    .where({ machinists: { shop_id: 1 }, rotations: { machine_id: 123}}) 
    .group(:bar) 
    .average('CAST(rotations.foo AS decimal)') 

唯一真正的區別是,我因爲機器不屬於機械師在where子句中分離出來。謝謝Albin!

回答

0

我覺得這個代碼更簡單一點,並採取更多的幫助從AR

Sprocket 
.joins(cogs: {rotations: :machinist}) 
.where({ machinists: { machine_id: 123, shop_id: 1 } }) 
.group(:bar) 
.average('CAST(rotations.foo AS decimal)') 

SELECT子句是不必要的,你沒有,因爲你只需要他們內部查詢,AR選擇值幫助您決定之後需要什麼。

我測試了這一點在我自己的一個項目使用類似的結構,但它是不完全一樣的車型所以有可能是一個錯字或東西在裏面,如果它不跑直線上升。我跑:

Activity 
.joins(locations: {participants: :stuff}) 
.where({ stuffs: { my_field: 1 } }) 
.group(:title) 
.average('CAST(participants.date_of_birth as decimal)') 

生產這種查詢

SELECT AVG(CAST(participants.date_of_birth as decimal)) AS average_cast_participants_date_of_birth_as_decimal, title AS title 
FROM `activities` 
INNER JOIN `locations` ON `locations`.`activity_id` = `activities`.`id` 
INNER JOIN `participants` ON `participants`.`location_id` = `locations`.`id` 
INNER JOIN `stuffs` ON `stuffs`.`id` = `participants`.`stuff_id` 
WHERE `stuffs`.`my_field` = 1 
GROUP BY title 

其中AR使得一個哈希看起來像這樣:

{"dummy title"=>#<BigDecimal:7fe9fe44d3c0,'0.19652273E4',18(18)>, "stats test"=>nil} 
+0

感謝您的答覆,這並沒有工作完全原樣是,但讓我得到了一個不需要原始SQL(除了演員表)之外的工作解決方案。我會盡快用最終解決方案更新這個問題。 – Kevin 2014-11-05 18:51:46