我有一个将用户加入帖子的范围,以便只获得具有可见帖子的用户。这适用于MySQL,但PG更严格,并且会抛出错误。
用户模型:
belongs_to :account
scope :have_posts, joins(:posts).where('posts.visible => true').group('users.id')
控制器:
@account.users.have_posts.each do |user|
# do stuff
end
错误:
(PGError:错误:列“users.account_id”必须出现在GROUP BY子句中或用于聚合函数:SELECT“users”。* FROM“users”INNER JOIN“posts”ON“posts”。“ user_id“=”users“。”id“WHERE(”users“.account_id = 1)AND(recommendations.approved = true)GROUP BY users.id)
它抱怨来自调用@account.users
的“users.account_id”(因为我显然不希望数据库中的所有用户)。
知道如何解决?
答案 0 :(得分:6)
问题是GROUP BY
子句。如果您使用此功能,则无法选择任何非聚合字段,因此SELECT "users".* [...]
不起作用。来自Postgres文档:
通常,如果表被分组,则未使用的列 除聚合表达式外,不能引用分组。
这样的事可能有用,虽然很乱:
scope :have_posts,
joins('inner join (select user_id from posts where visible = true group by user_id) users_with_posts on users_with_posts.user_id=users.id')
一种替代方法是使用MAX
或MIN
等聚合函数指定每个选定的字段,但这可能会使范围更长,功能更少。
答案 1 :(得分:0)
这应表示为where
条件而不是joins
,因为不需要来自posts
的任何数据。恕我直言更容易阅读:
scope :have_posts, -> {
where(
'EXISTS (SELECT 1 FROM posts p WHERE p.id = users.id AND visible = true)'
)
}
Ruby 2和Rails 3/4准备就绪。 PG优化器会尽快运行它。