2014-01-24 147 views
0

我正在努力解决Active Record连接问题。ActiveRecord多重连接?

我有这样的数据库表结构:

A - B - C - D - E 

A - F - E 

我想从一个得到所有的记录,如果这两种路径:

A - B - C - D - E 
A - F - E 

是满意。

我试图与活动记录:

A.joins(:B => {:C => {:D => :E}}, :F => :E) 
.where("some constraints on E and …") 

但这是不行的,因为所有作为内部生成的连接是这样的:

SELECT A.* 
FROM A 
INNER JOIN B ON A.b_id = B.id 
INNER JOIN C ON B.c_id = C.id 
INNER JOIN D ON C.d_id = D.id 
INNER JOIN E ON D.e_id = E.id 
INNER JOIN F ON A.f_id = F.id 
INNER JOIN E E_F ON E_F.f_id = F.id 
WHERE ("some constraints on E") 

我希望我没有错类型的东西在这里,但核心是,在生成的SQL语句中,两个路径都可以在ON子句中找到。

问题是,必须满足这两条路径才能从表A返回记录,对吗?

我需要一条从A返回两条路径的记录的语句。 最后,他们与uniq()独一无二。

我还试图merge()两个单独的选择/连接(路径A - B - C - D - E" and "A - F - E") but合并()does an intersection. The only solution that I have come up with, is to +`两个单独的结果集,但问题是,我得到的阵列作为结果,因此我不能使用(雷)分页。 第二,是不是在结果集越来越大的一个很好的解决方案。

我会很感激任何提示。 谢谢!

回答

2

我有,你可能会用手工巧妙地结束了的感觉精心加入此处:

SELECT A.* 
FROM A 
LEFT JOIN (B ON A.b_id = B.id 
    INNER JOIN C ON B.c_id = C.id 
    INNER JOIN D ON C.d_id = D.id 
    INNER JOIN E ON D.e_id = E.id) 
LEFT JOIN (F ON A.f_id = F.id 
    INNER JOIN E E_F ON E_F.f_id = F.id) 
WHERE E_F.id is not null or E.id is not null and 
    („some constraints on E“) 

最好把它封装在一个范围内,当然。

可以惹上麻烦你通过˚F加入,因为它似乎是A和E两者的母公司 - 若F的has_manyË那么你会得到多行回A.

你会解决这种通过使用相关子查询(半连接):

SELECT A.* 
FROM A 
LEFT JOIN (B ON A.b_id = B.id 
    INNER JOIN C ON B.c_id = C.id 
    INNER JOIN D ON C.d_id = D.id 
    INNER JOIN E ON D.e_id = E.id) 
WHERE E.id is not null and 
EXISTS (SELECT NULL FROM E E_F WHERE E_F.F.id = A.F_ID) 
    („some constraints on E“) 

注意,F可从查询被淘汰,因为F_ID存在于A和E.

对于整洁的缘故你可能使这两个加入半连接...

SELECT A.* 
FROM A 
WHERE (EXISTS (SELECT NULL FROM E E_F WHERE E_F.F.id = A.F_ID) OR 
     EXISTS (SELECT NULL FROM B 
       INNER JOIN C ON B.c_id = C.id 
       INNER JOIN D ON C.d_id = D.id 
       INNER JOIN E ON D.e_id = E.id 
       WHERE A.b_id = B.id)) 
    („some constraints on E“) 

弹出它变成一个范围...

scope :relates_to_e, -> {where("(EXISTS (SELECT NULL 
              FROM E E_F 
              WHERE E_F.F.id = A.F_ID) OR 
            EXISTS (SELECT NULL 
              FROM B 
              INNER JOIN C ON B.c_id = C.id 
              INNER JOIN D ON C.d_id = D.id 
              INNER JOIN E ON D.e_id = E.id 
              WHERE A.b_id = B.id))"} 

这不是很漂亮,但它会提高工作效率,并保持不整洁的范围。

A.relates_to_e.where(„some constraints on E and …“) 
+0

非常感谢你的揭示提示!您需要的解决方案的核心是EXISTS或OR组合。最后,我将范围定义为带参数的lambda表达式。 (我不想打扰所有的细节;-) –

+0

再次感谢! :-) 它就像一个魅力! –