在自联接表中的两个外键之间进行搜索的查询

Posted

技术标签:

【中文标题】在自联接表中的两个外键之间进行搜索的查询【英文标题】:query to search between two foreign keys in a self join table 【发布时间】:2021-09-25 06:40:57 【问题描述】:

用户表中的示例数据

rails 控制台中的预期结果,father.childrenmother.children 应该返回同一组对象:

father = User.first
father.children
=> #<ActiveRecord::Associations::CollectionProxy [#<User id: 3, name: "son", father_id: 1, mother_id: 2>, #<User id: 4, name: "daughter", father_id: 1, mother_id: 2>]>
mother = User.find(2)
mother.children
=> #<ActiveRecord::Associations::CollectionProxy [#<User id: 3, name: "son", father_id: 1, mother_id: 2>, #<User id: 4, name: "daughter", father_id: 1, mother_id: 2>]>

这是我现在在 User.rb 模型中的关联。如果我执行father.children,它将返回预期结果,因为foreign_key 指的是father_id。但它不适用于mother.children,因为它不引用mother_id

 has_many :children, foreign_key: "father_id", class_name: "User"
 belongs_to :mother, class_name: "User", optional: true
 belongs_to :father, class_name: "User", optional: true

我有什么办法吗

foreign key: "father_id" OR "mother_id"

我也尝试在关联中进行查询,但似乎无法理解它。

 has_many :children, ->  where("father_id = id OR mother_id = id") , class_name: "User"

【问题讨论】:

在关联中使用查询时遇到什么问题? 我认为这应该可行:has_many :children, -&gt;(user) where("father_id = :id OR mother_id = :id", id: user.id) , class_name: "User" User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."user_id" = ? AND (father_id = 1 OR mother_id = 1) /* loading for inspect */ LIMIT ? [["user_id", 1], ["LIMIT", 11]] 这是返回的内容。问题是当我使用查询时,即使我没有在查询中指定,它也会自动执行WHERE "users"."user_id" 按照下面的答案建议添加 unscope 应该可以解决问题。 是的,has_many :children, -&gt;(user) unscope(:where).where("father_id = :id OR mother_id = :id", id: user.id) , class_name: "User" 收到了,非常感谢! 【参考方案1】:

您可以取消该查询创建的默认范围,然后使用用户 ID 过滤子行:

has_many :children,
  ->(user)  unscope(:where).where('father_id = :id OR mother_id = :id', id: user.id) ,
  class_name: "User"

为什么是unscope?如果不删除它,您的代码将产生如下两个 SQL 查询:

SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
SELECT "users".* FROM "users" WHERE "users"."user_id" = ? AND "users"."father_id" = ?  [["user_id", 1], ["father_id", "1"]]

User.first.children 时 - 至少在 Rails 6.1.4 中。

如您所见,第二个查询过滤了所有id 等于接收者 (1) 并且同时具有father_id 列等于接收者 (1) 的用户。看看你的代码,可能永远不会发生。

注意,如果您在声明 has_many 关系后并不真的需要将所有这些方法添加到您的模型中,那么您最好使用单个实例方法或范围(在最后一种情况下)。因为使用这种方法,您会覆盖默认行为(无处记录),即通过该表中的主键过滤另一个表中的行。

【讨论】:

收到has_many :children, -&gt;(user) unscope(:where).where("father_id = :id OR mother_id = :id", id: user.id) , class_name: "User" 非常感谢!

以上是关于在自联接表中的两个外键之间进行搜索的查询的主要内容,如果未能解决你的问题,请参考以下文章

Oracle DB 使用连接显示多个表中的数据

Oracle 存储函数与查询中的联接

MySQL 自联接表 Next/Prev 行性能

优化按联接表中的字段对结果进行分组的查询

联接查询不适用于表中的所有元素

如何在两个表之间创建正确的联接?