2011-08-18 66 views
3

我有一個模型(Feature),可以有很多Assets。這些Assets每個都有一個issue_date。無論Assets是否有 - 最好帶有一個查詢,我都在努力處理看起來像是簡單的ActiveRecord查詢到查找所有Features及其Assets與明天的issue_dateRails 3:ActiveRecord query with:只包含返回在包含表中具有相關值的結果?

這是我的查詢現在。

Feature.includes(:assets).where(:assets => { :issue_date => Date.tomorrow }) 

不幸的是,這僅返回Assets明天的issue_dateFeatures。更奇怪的是,生成的SQL看起來像這樣(明天顯然是19日)。

SELECT `features`.* FROM `features` WHERE `assets`.`issue_date` = '2011-08-19' 

不應該有一個LEFT JOIN在那裏嗎?這就是我要做的事情。使用joins而不是includesINNER JOIN,但那不是我想要的。奇怪的是,似乎我得到了一種行爲類型INNER JOIN。當我運行上面includes查詢,這是吐出了實際的SQL看起來是這樣的......

SELECT `features`.`id` AS t0_r0, `features`.`property_id` AS t0_r1, 
    // every other column from features truncated for sanity 
    `assets`.`feature_id` AS t1_r1, `assets`.`asset_type` AS t1_r2, 
    // all other asset columns truncated for sanity 
FROM `features` 
LEFT OUTER JOIN `assets` ON `assets`.`feature_id` = `features`.`id` 
WHERE `assets`.`issue_date` = '2011-08-19' 

其中看起來像它應該工作的權利,但事實並非如此。我得到只有FeaturesAssets與明天的issue_date。任何想法我做錯了什麼?

我已經試過了年紀,Rails的做這件事的方式V2 ...

Feature.find(:all, 
      :include => :assets, 
      :conditions => ['assets.issue_date = ?', Date.tomorrow]) 

這給了我同樣的結果。有一個Feature我知道明天沒有任何Assets,它不在該列表中。

我也探索過,發現了類似的問題,但我似乎無法找到解釋我看到的這種相反的行爲的問題。

編輯:我是所以關閉。這使我得到了所有的Feature對象。

Feature.joins("LEFT OUTER JOIN assets on assets.feature_id = feature.id AND asset.issue_date = #{Date.tomorrow}") 

,然而,讓我捆綁到對象的匹配Assets。使用feature作爲查詢中的返回項目,feature.assets會再次調用數據庫,這是我不想要的。我想feature.assets只返回那些我在LEFT OUTER JOIN調用中指定的那些。我還需要對我的查詢做什麼?

+0

如果issue_date是資產表中的字段,那麼您如何期待特定issue_date的查詢返回沒有任何資產的功能? – asc99c

+0

如果我的帖子在這方面不明確,我表示歉意。如果**這樣的「資產」存在,我想要列出所有的「特徵」以及特定日期**的「資產」;否則,只是「功能」。 –

+1

哦,對不起,我明白了,你確實解釋了它,但我認爲我迷路了,讀了導軌生成的查詢。 issue_date是針對外連接的查詢,而不是對結果集的查詢。 – asc99c

回答

3

我認爲這會讓我得到我需要的東西,但事實並非如此。調用feature.assets(將feature作爲查詢返回的項目)執行另一個查詢以查找與feature相關的所有assets

Feature.joins("LEFT OUTER JOIN assets on assets.feature_id = feature.id AND asset.issue_date = #{Date.tomorrow}") 

所以這裏有什麼工作。似乎也有點清潔。我的Feature型號已經設置了一個has_many :assets。我已經設置了另一個has_many :tomorrows_assets的關聯,它指向Assets,但帶有條件。然後,當我要求Feature.allFeature.name_of_scope時,我可以指定.includes(:tomorrows_assets)。冠軍得主,雞晚餐。

has_many :tomorrows_assets, 
    :class_name => "Asset", 
    :readonly => true, 
    :conditions => "issue_date = '#{Date.tomorrow.to_s}'" 

我能夠成功查詢Features得到我需要的東西包括它,只有當它指定的條件匹配(我已經設置:readonly,因爲我知道我永遠也不會想編輯Assets這樣) 。這是一次IRB會議,展示魔術。

features = Feature.includes(:tomorrows_assets) 
feature1 = features.find_all{ |f| f.name == 'This Feature Has Assets' }.first 
feature1.tomorrows_assets 
=> [#<Asset id:1>, #<Asset id:2>] 

feature2 = features.find_all{ |f| f.name == 'This One Does Not' }.first 
feature2.tomorrows_assets 
=> [] 

而且所有在只有 SQL查詢。

0

你試過:

Feature.joins(:assets).where(:issue_date => Date.tomorrow); 

的蒞臨指導建議方法用於減少對輔助表查詢的數量,而不是投身於你嘗試的方式,兩個表中包含。

http://guides.rubyonrails.org/active_record_querying.html

+0

使用你的查詢會抱怨說'asset_type'不是'Features'的一部分,所以我重新編寫了最後一個where子句,用於包裝'assets'的散列(就像我查詢的最後一部分)。運行它會執行一個'INNER JOIN',並得到與上面相同的結果。看起來我需要的是一種指定條件以直接匹配'OUTER JOIN'的方式。 –

1

您必須指定SQL的外連接自己,joins方法只使用內部連接。

Feature.joins("LEFT OUTER JOIN assets ON assets.feature_id = features.id"). 
where(:assets => {:issue_date => Date.tomorrow}) 
+1

該查詢還省略了沒有任何符合「資產」標準的「資產」的「特徵」。如果我可以在'joins'字符串中指定issue_date條件,那麼怎麼辦?我可以這樣做嗎? –

1

我有一個非常類似的問題,並設法解決它使用以下查詢;

Feature.includes(:assets).where('asset.id IS NULL OR asset.issue_date = ?', Date.tomorrow) 

這將加載所有功能,不管它是否有任何資產。調用feature.asset將返回一組資產(如果有的話,不需要運行其他查詢)

希望能幫助別人!