0

我正在尝试进行具有 NOT IN 组件的多表连接。表是

帖子 -> 术语关系 -> 术语

Post
  has_many :term_relationships
  has_many :terms, :through => :term_relationships

TermRelationship
  belongs_to :post
  belongs_to :term

Term
  has_many :term_relationships
  has_many :posts, :through => :term_relationships

目标是获取除“精选”中的所有帖子之外的所有帖子。我当前的查询看起来像:

WpPost.includes(:terms).where("terms.term NOT IN (?)", ["featured"])

如果它附加的唯一术语是“特色”,这将非常有用。如果帖子属于“精选”和“真棒”,它仍然会因为“真棒”而显示。

无论如何要完全排除一行?它需要子查询吗?如果是这样,我将如何在 Rails 中做到这一点?

谢谢大家!贾斯汀

4

2 回答 2

1

你滥用includes. 这是为了急切加载,而不是为了加入!

但你的方法是对的。它可以用于您的情况。NOT IN (?)但是即使合乎逻辑,Rails 也不会发出嵌套请求。您将获得 2 个查询(您将获得NOT IN (id1, id2....,)而不是NOT IN (SELECT ....))。

所以我建议你使用squeel gem

常规 AR 代码(也可以用 squeel 美化):

featured_posts = WpPost.joins(:terms).where(terms:{term: ['featured']}).uniq

然后使用 sqeel 的力量:

WpPost.where{id.not_in featured_posts}

in并且not_in也被称为>>and<<但我不想吓到任何人)

注意使用块和符号的缺失。


SQLite 下 基于Chinook 数据库的一些测量:

> Track.all
  Track Load (35.0ms)  SELECT "Track".* FROM "Track"

joins和的关系like

oldie = Track.joins{playlists}.where{playlists.name.like_any %w[%classic% %90%]}

这是NOT IN

> Track.where{trackId.not_in oldie}.all
  Track Load (37.5ms)  SELECT "Track".* FROM "Track" WHERE "Track"."trackId" 
  NOT IN (SELECT "Track"."TrackId" FROM "Track" INNER JOIN "PlaylistTrack" ON
    "PlaylistTrack"."TrackId" = "Track"."TrackId" INNER JOIN "Playlist" ON 
    "Playlist"."PlaylistId" = "PlaylistTrack"."PlaylistId"
     WHERE (("Playlist"."name" LIKE '%classic%' OR "Playlist"."name" LIKE '%90%')))

供参考:

Track.where{trackId.not_in oldie}.count # => 1971
Track.count # => 3503
# join table:
PlaylistTrack.count # => 8715

结论:我没有看到由NOT IN. 35.0 与 37.5 没有明显区别。几次 35.0 变成了 37.5,反之亦然。

于 2012-05-30T06:30:13.797 回答
0

一种选择是进行 OUTER JOIN 并将特色参数放在那里。然后,您只需选择未加入任何术语的所有帖子。我不知道以简单的“Rails 方式”来做这件事的任何方式,但是使用一些额外的 SQL 你可以这样做:

Post.joins("LEFT OUTER JOIN term_relationships ON posts.id = term_relationships.post_id
            LEFT OUTER JOIN terms ON term_relationships.term_id = terms.id AND terms.term = ?", "featured").
     where("terms.id IS NULL")
于 2012-05-30T05:54:47.123 回答