【问题标题】:LEFT or FULL JOIN with Active Record使用 Active Record 的 LEFT 或 FULL JOIN
【发布时间】:2014-02-20 23:55:49
【问题描述】:

我有 5 个模型:用户、关键字、问题、关联和问题状态。

  • User 和 Keyword 是通过关联关联的(相同的关键字可以是 由多个用户添加,反之亦然)
  • 关键字和问题通过 has_many belongs_to 相关联(关键字 可以有很多问题,一个问题属于一个关键字)
  • User 和 Question 由 question_status 关联(用户可以标记 已回答、已删除等问题)

所以关系是:

  1. 一个用户通过关联有很多关键字
  2. 一个关键字通过关联有很多用户
  3. 关键字有很多问题
  4. 问题属于关键字
  5. 用户可以通过 question_status 为许多问题设置状态
  6. 一个问题可以由多个用户通过 question_status 分配状态

我必须构建 5 个模型,因为多个用户可以添加相同的关键字。因此,我必须将用户和关键字彼此分开,并通过关联将它们关联起来。多个用户在同一个问题上也可以有不同的标签(已回答、已删除、已归档等)。所以我必须与问题表分开维护这个状态。

模型是 -

class User < ActiveRecord::Base
  has_many :associations, dependent: :destroy
  has_many :keywords, :through => :associations

  has_many :question_statuses, dependent: :destroy
  has_many :questions, :through => :question_statuses

class Keyword < ActiveRecord::Base
  has_many :questions, dependent: :destroy

  has_many :associations, dependent: :destroy
  has_many :users, :through => :associations

class Question < ActiveRecord::Base
  belongs_to :keyword

  has_many :question_statuses, dependent: :destroy
  has_many :users, :through => :question_statuses

class Association < ActiveRecord::Base
  belongs_to :keyword
  belongs_to :user

class QuestionStatus < ActiveRecord::Base
  belongs_to :question
  belongs_to :user

我需要在 ActiveRecord 中创建一个 JOIN 查询,该查询将为用户(例如 users.id = 2)针对用户在其帐户中添加的关键字提供问题,不包括已删除或回答的问题,例如在 question_statuses 表中已删除 = t 或已回答 = t。

仅当用户标记问题时,才会将记录添加到 question_statuses。否则, question_statuses 将没有该用户的任何记录。

我们将不胜感激。

【问题讨论】:

  • 您提到已删除 = t 并已回答 = t。那些是 Rails 中的布尔字段吗?如果您使用显式文本字段而不是布尔字段,我建议您切换到使用布尔字段,以便 Rails 了解您打算在其中存储的信息类型。
  • 它们是布尔字段。

标签: ruby-on-rails activerecord join associations


【解决方案1】:

编辑:根据 OP 的反馈替换答案

这是我认为应该这样做的 ActiveRecord 语法:

Question.joins("LEFT OUTER JOIN question_statuses ON question.id = question_statuses.question_id AND question_statuses.user_id = #{ActiveRecord::Base.connection.quote(user_id)}").where(question_statuses: {user_id: nil})

相当于SQL:

SELECT * from questions LEFT OUTER JOIN question_statuses ON question.id = question_statuses.question_id AND question_statuses.user_id = 2 WHERE question_statuses.user_id IS NULL;

【讨论】:

  • 这将创建一个内部联接,但我认为我需要一个左联接或完全联接,因为 question_statuses 没有任何用户记录,除非该用户将问题标记为已回答或已删除。根据用户列表中的关键字,从问题表中为用户显示问题。我怎样才能在你的答案中加入左键?
  • 如果我正确理解您的评论,您想要的是用户尚未设置任何状态的所有问题?
  • 你是对的,但你的答案假设 question_statuses 包含所有问题,无论用户是否标记它。如果是这种情况,那么您的解决方案将起作用。您的解决方案导致以下SELECT "questions".* FROM "questions" INNER JOIN "question_statuses" ON "questions"."id" = "question_statuses"."question_id" WHERE "question_statuses"."user_id" = 2 问题与 question_statuses 形成内部联接,但如果用户未标记任何问题,则 question_statuses 将没有任何内容。问题从问题表中显示给用户。
  • 有道理。我将不得不编辑我的答案以考虑该结构。
  • 即使使用 LEFT OUTER JOIN,我也无法使其工作,不知道为什么!我能够使用以下 SQL 获得结果。但不确定如何在 ActiveRecord 中编写它。 select questions.* from questions LEFT JOIN question_statuses ON questions.id = question_statuses.question_id where questions.id NOT IN (select question_id from question_statuses where question_statuses.deleted = 't')
【解决方案2】:

2 种方法

1.使用表名

Question.join(question_statuses: :users).where('users.id = 2').where('question_statuses.deleted is true').where('question_statuses.answered is true')

2.使用 AREL

join 与上面相同,但 where 子句会略有不同,您可能需要在脚本/控制台中玩弄

【讨论】:

  • 感谢您的及时回复。在上面的答案中,您的意思是 question_statuses.deleted 是错误的,因为我需要排除它们。类似的回答。对吗?
  • @user2376032 - 我认为除非我进行左连接,否则这将不起作用,因为 question_statuses 将只有那些已被用户标记为已删除或已回答的记录。如果用户尚未标记任何问题,则上面的查询将返回零记录,因为它使用 question_statuses 进行了 INNER JOIN。知道如何进行 LEFT JOIN 吗?
猜你喜欢
  • 1970-01-01
  • 2018-02-28
  • 2020-03-07
  • 2013-03-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多