我有两个表users
和posts
,他们有has_many
的关联。我想在单个查询中获取users
和posts
的详细信息。我能够管理sql查询,但我不想在代码中使用原始查询(使用execute
方法),因为我认为这是一件简单的事情,可以使用活动记录编写。
这是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
在这里没有帮助,因为我正在处理大数据。
任何人都可以帮助我吗?
答案 0 :(得分:3)
如果您只想要那些特定的列而不是其他任何内容,那么这将起作用
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")
这将返回ActiveRecord::Relation
User
个具有post_id
,post_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
,其中包含两种有用的方法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
,其中键是列名,以及该记录的值或行值。
答案 1 :(得分:2)
users = User.joins(:posts).includes(:posts).where(id: [1, 2, 3])
将为所有用户提供他们的帖子。
然后你可以随心所欲地做任何事情,但是要访问第一个检索到的用户的帖子数据
first_user_posts = users.first.posts # this will not make additional DB queries as you used includes and data is already added
joins
在SQL INNER JOIN
语句
includes
加载内存中的所有posts
答案 2 :(得分:1)
我有两个表用户和帖子,他们有关联 有很多。我想在一个单独的内容中获取用户和帖子的详细信息 查询。
可以使用像
这样的包含来完成users = User.includes(:posts).where({posts: {user_id: [1,2,3]}})
根据您的要求,您可以使用其他eager_load
和preload
,以获得更多https://blog.arkency.com/2013/12/rails4-preloading/