ruby-on-rails - 如何在事件记录中编写子查询?

标签 ruby-on-rails ruby postgresql activerecord

我有两个表 usersposts,它们有 has_many 的关联。我想在单个查询中获取 usersposts 的详细信息。我能够管理 sql 查询,但我不想在代码中使用原始查询(使用 execute 方法),因为我认为这很简单,可以使用 active 编写记录。

这是sql查询

SELECT a.id, a.name, a.timestamp, b.id, b.user_id, b.title
FROM users a
INNER JOIN (SELECT id, user_id, title, from, to FROM posts) b on b.user_id = a.id
where id IN ( 1, 2, 3);

我认为 includes 在这里没有帮助,因为我正在处理大数据。 谁能帮帮我?

最佳答案

如果您只想要那些特定的列而别无其他,那么这将起作用

User.joins(:post)
 .where(id: [1,2,3])
 .select("users.id, users.name, users.timestamp, 
          posts.id as post_id, posts.user_id as post_user_id, 
          posts.title as post_title") 

这将返回 User 对象的 ActiveRecord::Relation,具有 post_idpost_user_id 的虚拟属性(不确定为什么需要这个,因为您已经选择了 users.id) 和 post_title

产生的查询将是

   SELECT users.id, 
          users.name, 
          users.timestamp, 
          posts.id as post_id,
          posts.user_id as post_user_id, 
          posts.title as post_title
   FROM users
   INNER JOIN posts on posts.user_id = users.id
   where users.id IN ( 1, 2, 3);

请注意,您可能有多个 User 对象,每个对象对应一个 Post,就像 SQL 查询一样。

您可以使用 joins 的字符串版本执行您的精确查询,例如

User.joins("INNER JOIN (SELECT id, user_id, title, from, to FROM posts) b on b.user_id = users.id")
 .where(id: [1,2,3])
 .select("users.id, users.name, users.timestamp, 
          b.id as post_id, b.user_id as post_user_id, 
          b.title as post_title") 

此外,为了避免一些开销,您可以使用 arel 代替,例如

 users_table = User.arel_table
 posts_table = Post.arel_table

 query = users_table.project(Arel.star)
           .join(posts_table)
             .on(posts_table[:user_id].eq(users_table[:id]))
           .where(users_table[:id].in([1,2,3]))
 ActiveRecord::Base.connection.exec_query(query.to_sql)

这将返回一个 ActiveRecord::Result,其中包含 2 个有用的方法 columns(选择的列)和 rows。您可以将其转换为 Hash(#to_hash),但请注意任何具有重复名称的列(例如 id)将相互覆盖。

您可以通过在 project 部分指定要选择的列来解决此问题。例如您当前的查询将是:

query =  users_table.project(
    users_table[:id],
    users_table[:name],
    users_table[:timestamp],
    posts_table[:id].as('post_id'),
    posts_table[:user_id].as('post_user_id'),
    posts_table[:title].as('post_title')
).join(posts_table)
   .on(posts_table[:user_id].eq(users_table[:id]))
.where(users_table[:id].in([1,2,3]))

ActiveRecord::Base.connection.exec_query(query.to_sql).to_hash

由于没有任何名称发生冲突,现在可以将其结构化为一个漂亮的 Hash,其中键是该记录的列名和值或行值。

关于ruby-on-rails - 如何在事件记录中编写子查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50640972/

相关文章:

javascript - Rails cookie 对象、Cookie HTTP header 和 document.cookie 之间的关系

ruby-on-rails - Twitter Bootstrap 图标不显示 - 我做错了什么?

ruby-on-rails - 删除 Rails 模型中的关系

postgresql - 从标准输入复制在 liquibase 中不起作用

ruby-on-rails - 载波上传图片

ruby - 如何在 vim 的 ruby​​ 执行之间保存变量?

ruby - 如何使用 watir 等待众多条件之一

postgresql - Qt 程序在连接到 QPSQL 失败时崩溃

postgresql - 我运行虚拟机的事实是否会改变我的常规 IP 地址的白名单状态?

ruby-on-rails - 如何在Rails中使用json更新nested_attributes?