导轨|在连接查询中添加条件

时间:2016-01-04 13:52:19

标签: ruby-on-rails rails-activerecord

是否可以在连接查询中添加条件?

例如,我想构建下一个查询:

select * from clients
left join comments on comments.client_id = clients.id and comments.type = 1

Client.joins(:comments).all仅生成:

select * from clients
left join comments on comments.client_id = clients.id

PS。 Client.joins("LEFT JOIN comments on comments.client_id = clients.id and comment.type = 1")并不好。

2 个答案:

答案 0 :(得分:1)

你可以这样做:

Client.left_outer_joins(:comments)
  .where(comments: { id: nil })
  .or(Client.left_outer_joins(:comments)
    .where.not(comments: { id: nil })
    .where(comments: { type: 1 }))
什么能给你提供与你想要的东西相同的东西:

SELECT "clients".* 
FROM "clients" 
  LEFT OUTER JOIN "comments" 
    ON "comments"."client_id" = "clients"."id" 
WHERE "comments"."id" IS NULL 
  OR ("comments"."id" IS NOT NULL) AND "comments"."type" = 1

更新

实际上,这不起作用,因为rails关闭了括号,不在类型的评估之外。

更新2

如果您的评论类型很少且不太可能会改变其值,您可以通过以下方式解决:

class Client < ApplicationRecord
  has_many :comments
  has_many :new_comments,  -> { where comments: { type: 1 } }, class_name: Comment
  has_many :spam_comments, -> { where comments: { type: 2 } }, class_name: Comment
end

class Comment < ApplicationRecord
  belongs_to :client
end

现在您可以在模型中使用这种新关系:

Client.left_joins(:comments)

给出:

SELECT "clients".*
FROM "clients"
  LEFT OUTER JOIN "comments" 
    ON "comments"."client_id" = "clients"."id"


Client.left_joins(:new_comments)

给出:

SELECT "clients".*
FROM "clients"
  LEFT OUTER JOIN "comments"
    ON "comments"."client_id" = "clients"."id" AND "comments"."type" = ?  
/*[["type", 1]]*/


Client.left_joins(:spam_comments)

给出相同的查询:

SELECT "clients".*
FROM "clients"
  LEFT OUTER JOIN "comments"
    ON "comments"."client_id" = "clients"."id" AND "comments"."type" = ?  
/*[["type", 2]]*/


Client.left_joins(:new_comments).where name: 'Luis'

给出:

SELECT "clients".*
FROM "clients"
  LEFT OUTER JOIN "comments"
    ON "comments"."client_id" = "clients"."id" AND "comments"."type" = ?
WHERE "clients"."name" = ?
/*[["type", 1], ["name", "Luis"]]*/

注:

我尝试在原始的has_many关系中使用参数,如...

has_many :comments, -> (t) { where comments: { type: t } }

但这给了我一个错误:

ArgumentError:关联范围&#39;评论&#39;是实例相关的(范围块采用参数)。不支持预加载实例相关的范围。

答案 1 :(得分:0)

Client.joins(:comments).where(comments: {type: 1})

试试这个