ruby-on-rails - Rails - Activerecord : Find all records which have a count on has_many association with certain attributes

标签 ruby-on-rails activerecord

一个用户有多个身份。

class User < ActiveRecord::Base
    has_many :identities
end

class Identity < ActiveRecord::Base
    belongs_to :user
end

一个身份有一个 confirmed:boolean柱子。我想查询只有一个身份的所有用户。这个身份也必须被证实是假的。

我试过这个
User.joins(:identities).group("users.id").having( 'count(user_id) = 1').where(identities: { confirmed: false })

但这会返回具有一个身份的用户 confirmed:false但如果他们被证实是真的,他们也可以有额外的身份。我只希望用户确认只有一个身份:false 并且没有其他身份确认属性为真。

我也试过这个,但显然它很慢,我正在寻找合适的 SQL 来在一个查询中完成这个。
  def self.new_users
    users = User.joins(:identities).where(identities: { confirmed: false })
    users.select { |user| user.identities.count == 1 }
  end

如果这已经得到回答,但我找不到类似的帖子,请提前道歉。

最佳答案

一种解决方案是使用 rails 嵌套查询

User.joins(:identities).where(id: Identity.select(:user_id).unconfirmed).group("users.id").having( 'count(user_id) = 1')

这是查询生成的 SQL
SELECT "users".* FROM "users"
INNER JOIN "identities" ON "identities"."user_id" = "users"."id"
WHERE "users"."id" IN (SELECT "identities"."user_id" FROM "identities"  WHERE "identities"."confirmed" = 'f')
GROUP BY users.id HAVING count(user_id) = 1

我仍然认为这不是最有效的方法。 虽然我只能生成一个 SQL 查询(意味着只对数据库进行一次网络调用),但我仍然需要进行两次扫描:一次扫描 USERS 表,一次扫描 IDENTITIES 表。这可以通过索引 identities.confirmed 来优化。列,但这仍然不能解决两次完整扫描的问题。

对于那些了解这里查询计划的人来说,它是:
     QUERY PLAN
-------------------------------------------------------------------------------------------
 HashAggregate  (cost=32.96..33.09 rows=10 width=3149)
   Filter: (count(identities.user_id) = 1)
   ->  Hash Semi Join  (cost=21.59..32.91 rows=10 width=3149)
         Hash Cond: (identities.user_id = identities_1.user_id)
         ->  Hash Join  (cost=10.45..21.61 rows=20 width=3149)
               Hash Cond: (identities.user_id = users.id)
               ->  Seq Scan on identities  (cost=0.00..10.70 rows=70 width=4)
               ->  Hash  (cost=10.20..10.20 rows=20 width=3145)
                     ->  Seq Scan on users  (cost=0.00..10.20 rows=20 width=3145)
         ->  Hash  (cost=10.70..10.70 rows=35 width=4)
               ->  Seq Scan on identities identities_1  (cost=0.00..10.70 rows=35 width=4)
                     Filter: (NOT confirmed)
(12 rows)

关于ruby-on-rails - Rails - Activerecord : Find all records which have a count on has_many association with certain attributes,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31719184/

相关文章:

ruby-on-rails - Rails 3.1.3 在使用 compass+sussy+haml+scss 编译 Assets 时在登台服务器中出错

ruby-on-rails - Rails/Ajax/错误处理

ruby-on-rails - has_one/has_many rails 与主键以外的备用源 ID 关联

sql - 有没有更有效的方法来使用 ActiveRecord 对此进行编码?

ruby-on-rails - Rails/PostgreSQL - 如何验证只能有两个用户 ID 的一种组合?

ruby-on-rails - 如何在 Ubuntu 16.04 上安装 mysql2 [错误 : Error installing mysql2: ERROR: Failed to build gem native extension.]

ruby-on-rails - 如何在 .map block 中使用 Rails link_to 帮助程序,以便输出是实际链接,而不是 HTML 的文本表示形式

ruby-on-rails - 使用 Arel 按频率排序记录

php - 如何在 codeigniter 中执行分组和计数

ruby-on-rails - 取消ajax请求导致rails抛出异常