如何用ActiveRecord实现关联子查询的UPDATE操作?
用ActiveRecord实现关联子查询的UPDATE操作
你的这条SQL完全可以用ActiveRecord实现,下面针对你的疑问逐一解决:
1. 关联分组统计的子查询
你可以先构建分组统计的子查询,再通过joins方法将其作为临时表关联到users表。
先构建和原SQL逻辑一致的子查询:
counts_subquery = Post.select(:user_id, 'count(*) AS num').group(:user_id)
然后通过原生SQL片段关联这个子查询:
User.joins("JOIN (#{counts_subquery.to_sql}) AS counts ON users.id = counts.user_id")
如果想完全用ActiveRecord的Arel接口(避免字符串拼接),可以这么写:
users = User.arel_table counts = counts_subquery.arel.as('counts') join_clause = users.join(counts).on(users[:id].eq(counts[:user_id])).join_sources User.joins(join_clause)
2. 为关联结果设置别名并比较值
当然可以设置别名,上面代码里的counts就是子查询临时表的别名,后续在where条件和update_all赋值里都能直接使用这个别名做值的比较。
完整的更新代码
结合起来,最终实现原SQL逻辑的ActiveRecord代码有两种写法:
方式一:混合原生SQL片段(直观易读)
counts_subquery = Post.select(:user_id, 'count(*) AS num').group(:user_id) User.joins("JOIN (#{counts_subquery.to_sql}) AS counts ON users.id = counts.user_id") .where('users.publications != counts.num') .update_all('users.publications = counts.num')
方式二:纯Arel接口(更符合ActiveRecord风格)
counts_subquery = Post.select(:user_id, 'count(*) AS num').group(:user_id) users = User.arel_table counts = counts_subquery.arel.as('counts') User.joins(users.join(counts).on(users[:id].eq(counts[:user_id])).join_sources) .where(users[:publications].not_eq(counts[:num])) .update_all(users[:publications].eq(counts[:num]))
这类操作的专业术语是JOIN子查询更新,以后搜索相关方案可以用这个关键词。
内容的提问来源于stack exchange,提问作者nimmolo
相关产品推荐
相关产品推荐

