【问题标题】:Rails - Find records that are not present another join tableRails - 查找不存在另一个连接表的记录
【发布时间】:2011-01-27 15:43:26
【问题描述】:

我正在尝试编写一个 ActiveRecord 语句,在其中查找 id 不存在于另一个表中的所有记录...

语法是什么?

 @events =  Event.find(:all, :include => :personals, 
                  :conditions => ["event.id != ? ", @user.personal.event_id ])

personals 是一个包含 user_id 和 event_id 的连接表......

所以我实际上是在尝试查找用户尚未添加到他们自己的个人记录集中的每个事件记录......

有没有更好的方法来写这个......不为空或什么?

【问题讨论】:

  • 您是否遇到特定错误,或者只是想知道这是否是最有效的方法?
  • 关系如何设置可以提供更好的答案?

标签: ruby-on-rails activerecord


【解决方案1】:

其他答案不适用于数十万或更多记录。这是一个纯 SQL 解决方案。

Rails 5+:

Event.left_outer_joins(:personals).where(personals: {event_id: nil})

这会检索所有没有关联个人的事件。

Rails 3+:

Event.joins('LEFT JOIN personals ON event.id = personals.event_id').where('personals.event_id IS NULL')

【讨论】:

  • 我不认为这是正确的。我知道他想获得不包含特定 ID 的条目。这也将跳过那些只有不同 id 的(id 必须以某种方式在查询中)
  • 谢谢——你是对的,我误读了这个问题。这回答了“鉴于活动有很多交友,我如何获得所有没有交友的活动”。我现在看到的问题是“给定事件有很多交友,而用户有很多交友,我如何获得不与某些用户分享任何交友的所有事件”。
【解决方案2】:

Nuby 提出的解决方案与以往一样正确。这是现代语法中的相同查询,可用于 Rails 3 及更高版本:

Event.where.not(id: @user.event_ids)

【讨论】:

  • 这将生成大量(几乎可以肯定是非法的)选择语句,其中 id 仅包含在文本中。你真的需要一些可以加入的东西。
  • @JamesMoore Event.where.not(id: @user.events.select(:id))
【解决方案3】:

我假设关系如下:

User: 
has_many :personals
has_many :events, :through => :personals

Event:
has_many :personals
has_many :users, :through => :personals

Personal:
belongs_to :event
belongs_to :user

我的解决方案是为用户“event_ids”使用自动创建的关联函数,该函数列出了 User.events 中的所有事件 ID。获取您要执行的操作的查询应该是:

Event.find(:all, :include => :personals, :conditions => ["events.id NOT IN (?)", @user.event_ids])

而且,除非您确实需要连接,否则您可以简化:

Event.find(:all, :conditions => ["events.id NOT IN (?)", @user.event_ids])

关键是 SQL 命令“NOT IN (x)”。另请注意,根据 SQL 约定,“events.id”是模型名称的复数。

希望这会有所帮助...

【讨论】:

  • 这不会生成两个 SQL 命令 - 一个收集? @user.event_ids,还有一个 NOT IN [all those ids] .. 这在很多情况下都很好,但如果有数十万个 @user.event_ids,那么生成纯 SQL 的东西是首选;对吗?
【解决方案4】:

目前为止最好的:

events = Event.left_joins(:personals)
events.where.not(personals: { event_id: @user.personal.event_id }).or(
  events.where(personals: { event_id: nil })
)

产生 SQL:

SELECT "events".* FROM "events" 
LEFT OUTER JOIN "personals" 
ON "personals"."event_id" = "events"."id" 
WHERE ("personals"."event_id" != $1 OR "personals"."event_id" IS NULL)

【讨论】:

    猜你喜欢
    • 2012-12-24
    • 2010-09-26
    • 2014-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-16
    相关资源
    最近更新 更多