如何找到同时拥有猫狗的用户?

我想在2个具有多对一关系的表中进行搜索,例如

class User << ActiveRecord::Base has_many :pets end class Pet << ActiveRecord::Base belongs_to :users end 

现在让我们说我有一些这样的数据

 users id name 1 Bob 2 Joe 3 Brian pets id user_id animal 1 1 cat 2 1 dog 3 2 cat 4 3 dog 

我想要做的是创建一个活动的记录查询,它将返回一个既有猫又有狗的用户(即用户1 – Bob)。

到目前为止,我的尝试是

 User.joins(:pets).where('pets.animal = ? AND pets.animal = ?','dog','cat') 

现在我明白为什么这不起作用 – 它正在寻找一只既是狗又是猫的宠物,所以什么都不回报。 我不知道怎么修改这个给我答案我想要的。 有没有人有什么建议? 这似乎应该很容易 – 它似乎不是一个特别不寻常的情况。

– -编辑 – –

我刚刚发现了Squeel,只是在这个问题上添加了一点点尾声 。 这允许你像这样构建一个子查询;

 User.where{id.in(Pet.where{animal == 'Cat'}.select{user_id} & id.in(Pet.where{animal == 'Dog'}.select{user_id})) 

这将是我的应用程序的方式。

使用子选择来约束结果:

 User.joins(:pets).where( 'id IN (SELECT user_id FROM pets WHERE animal = ?) AND id IN (SELECT user_id FROM pets WHERE animal = ?)', 'cat', 'dog') 

Andomar – 不幸的是,编写这样的查询并不一定总能按预期工作。 具体来说,有2只猫将导致用户出现,并且有3只宠物 – 比方说,2只猫和一只狗 – 会导致它们被排除在外。
我对ActiveRecord了解不多,但以下是可行的标准SQL语法:

 SELECT users.id FROM Users JOIN (SELECT user_id FROM Pets WHERE animal IN ('dog', 'cat') GROUP BY user_id HAVING COUNT(DISTINCT animal)) Pets ON Pets.user_id = Users.id 

通过计算宠物的不同“类型”( 'cat''dog' ),这与现有版本的工作方式不同。

通常的方法是在where子句中过滤猫或狗。 然后在user_id上进行group by ,并要求结果组having count(distinct pet.id) = 2

我不确定你在ActiveRecord中的表达方式; 这篇文章似乎包含一个解决方法。

对于这个问题,有很多方法可以得到你可以做的解决方案,如下…

 select dog_table.user_name from ( select * FROM users,pets where pets.user_id = users.id and pets.animal = 'dog' ) dog_table, ( select * FROM users,pets where pets.user_id = users.id and pets.animal = 'cat' ) cat_table where dog_table.user_id = cat_table.user_id 

这应该会有所帮助。 试试这个

从用户u,pet p1中选择你。*其中u.id = p1.user_id AND p1.animal =“cat”AND p1.user_id in(选择来自宠物的user_id,其中animal =’dog’)

我很少回答关于SO的问题,但我会尝试一下。 🙂

 SELECT name FROM users WHERE id IN (SELECT a.user_id FROM ( (SELECT user_id FROM pets WHERE animal = 'cat') a INNER JOIN (SELECT user_id FROM pets WHERE animal = 'dog') b ON a.user_id = b.user_id )); 

有很多方法可以做到这一点 – 上面的一些方法可行; 另外,这里有一个略微不同的方法,主要使用“视图” – 基本上,只是从你的通用’宠物’类inheritance成两个独立的类(猫和狗)。

 SELECT id, name FROM users INNER JOIN ( SELECT DISTINCT user_id as belongs_to FROM pets WHERE animal = 'dog' ) dog ON users.id = dog.belongs_to INNER JOIN ( SELECT DISTINCT user_id as belongs_to FROM pets WHERE animal = 'cat' ) cat ON users.id = cat.belongs_to 

这是另一种解决方案。 更多Rails友好..

 User.all(:select => "DISTINCT users.*", :joins=>[:pets, :pets], :conditions => ["pets.animal = ? AND pets_users.animal = ?", "cat", "dog"]) 

阅读本文 ,了解使用JOINGROUP BY + HAVING进行此类解决方案的相对优点。

请参阅此SO问题 ,详细讨论此问题。

你可以通过各种方式得到这个结果。

希望它对你有所帮助。 试试这个,

 SELECT id FROM (SELECT user_id AS id FROM users INNER JOIN pets ON pets.user_id=users.id GROUP BY pets.user_id,pets.animal HAVING COUNT(pets.user_id)>0 AND (pets.animal='cat' OR pets.animal='dog') )AS s GROUP BY id HAVING COUNT(id)>1