Sim*_*mon 5 postgresql ruby-on-rails
我正在开发一个应用程序,其中User有许多项目,并且Project有很多角色.Role有一个布尔filled属性来指示某人何时接受了该角色.
我想构建一个查询,它返回所有没有角色或具有已经填充的角色的项目.这是我到目前为止最接近的:
@user.projects.includes(:roles).where("roles.id IS NULL OR roles.filled IS TRUE").references(:roles)
Run Code Online (Sandbox Code Playgroud)
问题是roles.filled IS TRUE查询的一部分是匹配具有填充和未填充角色的项目.我需要这个只匹配所有角色都填充的项目.
搜索PostgreSQL文档,它看起来bool_and可能是要走的路,但我的SQL技能不是很好,我还没有设法让它工作.
我意识到我可以轻松地使用select或者这样做reject但我想通过查询数据库来保持它的效率.
有人可以提供一些建议吗?
更新:(简化)模型及其关系:
应用程序/模型/ user.rb
class User < ActiveRecord::Base
has_many :projects
end
Run Code Online (Sandbox Code Playgroud)
应用程序/模型/ project.rb
class Project < ActiveRecord::Base
belongs_to :user
has_many :roles
end
Run Code Online (Sandbox Code Playgroud)
应用程序/模型/ role.rb
class Role < ActiveRecord::Base
belongs_to :project
# `filled` is a boolean attribute with a default value of false
end
Run Code Online (Sandbox Code Playgroud)
您必须求助于聚合函数,因为条件适用于许多记录的组合( 的所有字段都roles.filled必须为 true)。因此,您将所有角色分组projects.id并检查是否every(roles.filled)为真:
这是一个建议:
@user.projects.
joins("left outer join roles on roles.project_id = projects.id").
group("projects.id").
having("every(roles.filled IS TRUE) OR every(roles.id IS NULL)")
select("projects.*")
Run Code Online (Sandbox Code Playgroud)
更新:好的,这是这个 SQL 背后的逻辑:
对于每个项目,我都会检查它是否没有 Roles.id 或只有 Roles.filled。不能使用 where 子句的原因
roles.id IS TRUE是,它只会在子句中进行分组和筛选之前选择这些行having,从而排除这些roles.filled行。换句话说,这相当于做roles.id is NULL AND Roles.filled IS TRUE