使用带有活动记录的连接表时如何连接模型的多个实例?

Sam*_*son 4 postgresql activerecord ruby-on-rails inner-join subquery

这适用于使用 PostgreSQL 的 Rails 5 / Active Record 5。

假设我有两个模型:ProductWidget. 一个Product has_many小部件和Widget has_many通过产品连接表叫products_widgets

我想写发现,与相关联的所有产品的查询与小部件id=37 ,并与小部件id=42

我实际上有一个 id 列表,但是如果我能写出上面的查询,我一般可以解决这个问题。

请注意,此查询的版本更容易是找到与相关联的所有部件要么与小部件id=37 与窗口小部件id=42,你可以写如下:

Product.joins(:products_widgets).where(products_widgets: {widget_id: [37, 42]})

但这不是我需要的。

GMB*_*GMB 5

作为初学者:在纯 SQL 中,您可以使用exists条件来表达查询:

select p.*
from product p
where 
    exists (
        select 1 
        from products_widgets pw 
        where pw.product_id = p.product_id and pw.widget_id = 37
    )
    and exists (
        select 1 
        from products_widgets pw 
        where pw.product_id = p.product_id and pw.widget_id = 42
    )
Run Code Online (Sandbox Code Playgroud)

在 Active Record 中,我们可以尝试直接在where条件中使用原始子查询:

product
    .where('exists(select 1 from products_widgets where product_id = product.product_id and widget_id = ?)', 37)
    .where('exists(select 1 from products_widgets where product_id = product.product_id and widget_id = ?)', 42)
Run Code Online (Sandbox Code Playgroud)

我认为使用.arel.exist也可能有效:

product
    .where(products_widgets.where('product_id = product.product_id and widget_id = ?', 37).arel.exists)
    .where(products_widgets.where('product_id = product.product_id and widget_id = ?', 42).arel.exists)
Run Code Online (Sandbox Code Playgroud)