【问题标题】:Rails ActiveRecord return records where id exists in related tableRails ActiveRecord 返回相关表中存在 id 的记录
【发布时间】:2013-01-07 01:54:57
【问题描述】:

我有一个客户模型和一个产品模型,其中一个客户有很多产品,一个产品属于一个客户。

我需要找到一个只有在 Product 表中有记录时才返回客户的查询

客户表

id |      name
--------------
 1 | Company A
 2 | Company B
 3 | Company C

产品表

id |      name |  client_id
---------------------------
 1 | Product A |         1
 2 | Product B |         1
 3 | Product C |         3
 4 | Product D |         3
 5 | Product E |         1

我只需要客户 1 3

比如

@clients = Client.where("client exists in products")  #something to this effect

【问题讨论】:

  • @clients = Client.joins(:products) 有效吗?我认为它会做一个 INNER JOIN,这是(我认为)你想要的
  • 这是个好问题,我会在控制台测试
  • @pjam 它似乎返回了所有加入客户的产品,因此我最终得到了重复的客户名称。有没有办法将结果限制在客户端?
  • @pjam 例如,我只想要 4 条记录,而不是 214,这是我在 products 表中拥有的产品数量。 214 是这 4 个客户的组合,但我只想退回 4 个客户,而不是那些客户加入的 214 产品。我希望这不会让任何人感到困惑。
  • 我得到了你想要的,但查询 Client.joins(:products) 正在返回一组客户,对吗?问题是你有重复的条目吗?

标签: ruby-on-rails activerecord active-record-query


【解决方案1】:

最简单但不是最快的:

Client.where(:id => Product.select(:client_id).map(&:client_id))

SQL 子查询(更快):

Client.where("EXISTS(SELECT 1 from products where clients.id = products.client_id)")

【讨论】:

  • 这是一个更好的答案,不会返回连接语句将包含的不必要的列。
  • 我真的很喜欢这个答案。第二个查询允许我与同一数据库中的非活动记录表进行比较。
【解决方案2】:

另一个可以做到这一点的宝石:activerecord_where_assoc(我是作者)

有了它:

Client.where_assoc_exists(:products)

如果您还必须指定某些产品,何时可以这样做:

Client.where_assoc_exists(:products, id: my_products.map(&:id))

没有宝石就很容易出错。

documentation 中了解更多信息。这是introductionexamples

【讨论】:

    【解决方案3】:

    这是另一个解决方案。这是一个类似于 Valery 的第二个解决方案的子查询,但没有写出 sql:

    Client.where(Product.where(client_id: Client.arel_table[:id]).exists)
    

    【讨论】:

    • 这对我不起作用(使用 postgresql 适配器);一直将 arel_table 参数解释为准备好的值,然后因为它不是一个而出错。
    • 我刚刚了解到,.exists 不是公共 API 的一部分。这在 4.1 之前一直有效,但在 4.2 上不再有效。
    【解决方案4】:

    这是使用Where Exists gem 的解决方案(披露:我是它的作者):

    Client.where_exists(:products)
    

    【讨论】:

    • 不错的宝石!看起来很优雅!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多