2008/5/24 Xin Zheng <<a href="mailto:xin@zenpow.com">xin@zenpow.com</a>>:<br>> I want to find a Monitor that is BOTH white and big.<br>><br>>My first shot at this:<br>>find(:all, :include => :features, :conditions => ["name IN ('white',<br>
>'big')" )<br>><br>>But this query will find Monitors that's EITHER white or big.<br><br><br>Yeah,<br>the short answer is;<br>"that's exactly what you've asked it to do"<br><br>
===========<br>Your db<br>===========<br>- Monitor#1<br>-- Feature#1 = big<br>-- Feature#2 = white<br>-- Feature#3 = small<br><br>- Monitor#2<br>-- Feature#4 = big<br><br>- Monitor#3<br>-- Feature#5 = white<br><br>- Monitor#4<br>
-- *no features*<br>===========<br><br>Doing an include gets you a left outer join on "features"<br>which creates a new line for each feature.<br>===========<br>- Monitor#1 & Feature#1(big)<br>- Monitor#1 & Feature#2(white)<br>
- Monitor#1 & Feature#3(small)<br>- Monitor#2 & Feature#4(big)<br>
- Monitor#3 & Feature#5(white)<br>- Monitor#4 & *no feature*<br>===========<br><br>Then you say<br>"name IN (white, big)"<br>===========<br>this grabs all those lines which satisfy your requirement<br>===========<br>
- Monitor#1 & Feature#1(big)<br>- Monitor#1 & Feature#2(white)<br>- Monitor#2 & Feature#4(big)<br>- Monitor#3 & Feature#5(white)<br>===========<br><br>Hence,<br>you don't get what you want.<br><br>And,<br>
you don't actually intend to ":include" these features anyway, (if you do, then my solution is wrong)<br>you're just using the :include, because it does the join automatically.<br><br>The right solution is debatable;<br>
can do it with subqueries, or a double "inner join"<br><br>but I think subqueries are the right way,<br>they look dirty, but it's exactly what you're asking for.<br><br>Hopefully MySQL will optimise it correctly.<br>
<br>condition_bit = "EXISTS(SELECT * FROM features WHERE monitor_id = <a href="http://monitors.id">monitors.id</a> & <a href="http://features.name">features.name</a> = ?)"<br>condition_string = ([condition_bit]*2).join(" AND ")<br>
conditions = [condition_string, "big", "white"]<br>Monitor.find(:all, :conditions => conditions)<br><br>my friend Freddy Cheung wrote a nice blog post about similar stuff:<br><a href="http://www.spacevatican.org/2008/4/29/include-and-conditions">http://www.spacevatican.org/2008/4/29/include-and-conditions</a><br>