2012-07-10 54 views
0

我有一個關於在ActiveRecord中形成查詢的問題,但也爲那些不熟悉ActiveRecord的人提供了SQL。如何調整ActiveRecord(或直接SQL)查詢以在包含WHERE子句的JOIN中包含零計數記錄

我有以下模型類:

class Shoe < ActiveRecord::Base 
    has_many :purchases 

    def self.available_shoes 
    #show all shoes that have been purchased less than num_in_stock 
    num_in_stock = 3 
    Shoe.includes(:purchases) 
     .group("purchases.shoe_id") 
     .having("COUNT(purchases.shoe_id) < ?", num_in_stock) 
    end 

    def self.available_shoes_for_user(user) 
    #show all available_shoes that a user hasn’t already purchased 
    Shoe.available_shoes.where("purchases.user_id != ?", user.id) 
    end 
end 

如預期的,因爲它會返回已比現貨供應量購買更少的時間所有的鞋(在這種情況下3)Shoe.available_shoes工作方法,包括購買了零次的鞋子。

問題出在我打電話Shoe.available_shoes_for_user(user)時,它會顯示所有已有購買的鞋子,但它沒有顯示有零購買的可用鞋子。

我已提取下面的原始SQL:

#Shoe.available_shoes 
SELECT shoes.*, purchases.* FROM shoes LEFT OUTER JOIN purchases ON purchases.shoe_id = shoes.id GROUP BY shoe_id HAVING COUNT(purchases.shoe_id) < 3 

#Shoe.available_shoes_for_user(User.find(5)) 
SELECT shoes.*, purchases.* FROM shoes LEFT OUTER JOIN purchases ON purchases.shoe_id = shoes.id WHERE (purchases.user_id != 5) GROUP BY shoe_id HAVING COUNT(purchases.shoe_id) < 3 

問題1:我怎樣才能Shoe.available_shoes_for_user(user)作爲工作打算(即,顯示購買的所有鞋子的3倍以上(包括零次),其客戶端尚未購買

問題2:從長遠來看,這將是解決這一問題的最佳解決方案時,有幾十萬/百萬雙鞋

提前致謝!

============================ 一個解決方案:(僅在MySQL工作不PostgreSQL的) 由於@Frederick Cheung爲指路

class Shoe < ActiveRecord::Base 
    has_many :purchases 

    def self.available_shoes 
    #show all shoes that have been purchased less than num_in_stock 
    num_in_stock = 3 
    Shoe.includes(:purchases) 
     .group("purchases.shoe_id") 
     .having("COUNT(purchases.shoe_id) < ?", num_in_stock) 
    end 

    def self.available_shoes_for_user(user) 
    #show all available_shoes that a user hasn’t already purchased 
    Shoe.available_shoes 
     .joins("LEFT OUTER JOIN purchases purchased_by_user ON purchased_by_user.shoe_id = shoes.id AND purchased_by_user.user_id = '#{user.id}'") 
     .where("purchased_by_user.id IS NULL") 
    end 
end 
+0

我假設你使用MySQL?你的代碼工作*(只對'.group'進行小的語法修改)*在PostgreSQL中很好。 – deefour 2012-07-10 04:22:16

+0

似乎沒有問題,因爲 'Shoe.includes(:purchases).group(「purchases.shoe_id」)。having(「COUNT(purchases.shoe_id)<?」,2)' 也顯示有零購買,因爲這會執行左外連接。 – prasvin 2012-07-10 05:23:37

+0

@Deefour是的,與MySQL合作。 – madhermit 2012-07-10 16:43:55

回答

1

如果鞋子沒有購買,左連接意味着對於該鞋子,結果集對於購買表中的所有列將具有NULL。

您正在應用where purchases.user_id != 5子句來刪除該用戶的購買交易,但也會過濾掉NULL行。你可以改變這種狀況,以

where purchases.id is null or purchases.user_id != 5 

但我想你想要的東西,這將仍然不行:如果鞋子已經被客戶和一些其他客戶購買本只想讓報告數量爲1,而不是2,而不是刪除該行共

您可以通過參加採購表中的第二次做到這一點

left outer join purchases on purchases.shoe_id = shoes.id 
left outer join purchases purchased_by_user on purchased_by_user.shoe_id = shoes.id and purchased_by_user.user_id = 5 

你的where子句則需要只是確保purchased_by_user.id is null,表示該數據庫可以找到無p用這個user_id的鞋的urchases

+0

你好,使用你的提示我能想出一個解決方案,我編輯了我原來的問題來顯示。我將把你的答案標記爲已接受。謝謝你的幫助。 – madhermit 2012-07-26 19:39:16