2012-05-21 43 views
7

我有2種型號高級SQL Rails中

class User < AR 
has_many :friends 
end 

class Friend < AR 
    # has a name column 
end 

我需要找到誰是既「喬」和朋友們所有用戶的「傑克」

任何想法我如何能在軌道做到這一點?

+0

對不起,我沒有仔細閱讀您的問題......刪除了我的不正確答案。 – Mischa

+0

@ muistooshort替換或者不工作 –

+0

您誤解了我對Mischa誤解的糾正,我們的評論也是這樣說的。 –

回答

3

一種選擇是將每個名稱作爲單個INNER JOINS的參數。在SQL它會是這樣的:

SELECT users.* FROM users 
INNER JOIN friends AS f1 
    ON users.id = f1.user_id 
    AND f1.name = 'Joe' 
INNER JOIN friends AS f2 
    ON users.id = f2.user_id 
    AND f2.name = 'Jack' 

既然是內部聯接,它只會顯示效果在用戶表可以同F1和F2結合。

而且在Rails中使用它,也許做這樣的事情:

class User < AR 
    has_many :friends 

    def self.who_knows(*friend_names) 
    joins((1..friend_names.length).map{ |n| 
     "INNER JOIN friends AS f#{n} ON users.id = f#{n}.user_id AND f#{n}.name = ?" }.join(" "), 
     *friend_names) 
    }) 
    end 
end 

,你可以接着調用是這樣的:

@users = User.who_knows("Joe", "Jack") 
1

可能的方法:User.all(:joins => :friends, :conditions => ["friends.name IN (?,?)", "Joe", "Jack"], :group => "users.id")然後遍歷數組以找到有2個朋友的用戶。

這是我嘗試爲自己解決類似問題時得到的最佳解決方案。如果你在純sql或ActiveRecord中找到方法 - 請告訴我!

1

雖然使用硬編碼的SQL由DanneManne的建議通常會工作,而且可能是你想要去的方式,它不一定是可組合的。只要你對錶名進行了硬編碼,你就會遇到一些問題,將其結合到其他查詢中,ActiveRecord可能會決定對錶進行別名。

因此,在一些額外的複雜性成本,我們可以使用一些AREL如下解決這個問題:

f = Friend.arel_table 
User. 
    where(:id=>f.project(:user_id).where(f[:name].eq('Joe'))). 
    where(:id=>f.project(:user_id).where(f[:name].eq('Jack'))) 

這將使用一對的子查詢來完成這項工作。

我相當肯定有一個使用連接的ARel解決方案,但我可以弄清楚如何在ARel中編寫該查詢,而不是如何使用該查詢作爲ActiveRecord查詢的基礎來取回用戶模型實例。

+0

這很棒,但這個確切的查詢不起作用。看看使用這種技術的其他解決方案。謝謝! –