如何在 Arel 中“存在于哪里”

Posted

技术标签:

【中文标题】如何在 Arel 中“存在于哪里”【英文标题】:How to do "where exists" in Arel 【发布时间】:2011-09-06 14:53:37 【问题描述】:

如何在 Arel 中执行包含“存在于何处”的查询?例如,在这样的查询中显示至少有一个订单的所有供应商:

SELECT *
FROM suppliers
WHERE EXISTS
  (SELECT *
    FROM orders
    WHERE suppliers.supplier_id = orders.supplier_id);

我在 Arel 文档 http://rubydoc.info/gems/arel/2.0.7/Arel/Nodes/Exists 中看到“存在”,但我无法使用它。

【问题讨论】:

有问题的关系运算符是semi-join。 我也对此感兴趣。然而,exists 节点似乎实际上已从最新版本的 ARel 中删除。不知道以后有没有计划。 【参考方案1】:

给你:

suppliers= Supplier.arel_table
orders= Order.arel_table
suppliers_with_orders = Supplier.where(
                          Order.where(orders[:supplier_id]
                                        .eq(suppliers[:id])).exists).to_sql =>
"SELECT `suppliers`.* FROM `suppliers` 
 WHERE (EXISTS (SELECT `orders`.* 
                FROM `orders` 
                WHERE `suppliers`.`id` = `orders`.`supplier_id`))"

不过,内部联接会以更简单但最终性能更低的方式完成此操作:

Supplier.joins :订单

【讨论】:

好一个!在您链接到关于not exists 的其他帖子之后,正要回答这个问题,再次感谢@pedrorolo 内部连接将完全不同,因为它将返回供应商记录的多个副本,每个订单一个。这是一场等待发生的性能灾难,尤其是当您将多个关联的存在性测试组合在一起时,其中 10 个订单、5 个付款和 20 个交付组合起来为您返回 1,000 条记录。 Exists 在几乎所有方面都更有效。【参考方案2】:

我认为你可以巧妙地为这个使用 counter_cache :

http://asciicasts.com/episodes/23-counter-cache-column

【讨论】:

以上是关于如何在 Arel 中“存在于哪里”的主要内容,如果未能解决你的问题,请参考以下文章

Arel:如何在 arel speak 中写 attr = NULL?

如何在 Arel 和 Rails 中进行 LIKE 查询?

如何使用ARel对子查询进行连接?

如何在初始 where 语句中使用 Arel::Nodes::TableAlias

如何在 Rails 中对 AREL 中的子查询进行连接

如何使用 arel/关系代数获取不同的值