[英]MySQL refactor select subqueries into joins
I have 4 separate select subqueries here that are just selecting 1 column I need – but I know this is inefficient.我在这里有 4 个单独的选择子查询,它们只选择了我需要的 1 列——但我知道这是低效的。
How can the same be achieved but with joins?除了连接之外,如何实现相同的功能? I've tried with subqueries inside joins with group by, but unfortunately haven't been able to get it working.我已经尝试在与 group by 的连接中使用子查询,但不幸的是无法让它工作。
SELECT [columns needed],
(SELECT posts.created_at FROM posts WHERE posts.thread_id = threads.id ORDER BY posts.created_at DESC LIMIT 1) as lastpost_created_at,
(SELECT users.username FROM posts INNER JOIN users on posts.user_id = users.id WHERE posts.thread_id = threads.id ORDER BY posts.created_at DESC LIMIT 1) as lastpost_username,
(SELECT users.avatar FROM posts INNER JOIN users on posts.user_id = users.id WHERE posts.thread_id = threads.id ORDER BY posts.created_at DESC LIMIT 1) as lastpost_avatar,
(SELECT COUNT(*) FROM posts WHERE posts.thread_id = threads.id) as replies
FROM threads
INNER JOIN posts ON threads.post_id = posts.id
INNER JOIN users ON posts.user_id = users.id
ORDER BY lastpost_created_at DESC
I'm not sure if I've interpreted correctly, but it seems like you want to get:我不确定我的解释是否正确,但您似乎想得到:
I've put together an SQLfiddle that I believe supplies all of these, query below:我已经整理了一个SQLfiddle ,我相信它提供了所有这些,查询如下:
select threads.id,
lastpost_created_at.lastpost,
posts.user_id,
/* posts.other_fields, */
users.avatar,
/* users.other_fields, */
post_counts.replies
from threads
left join
(
/* first we aggregate the posts by thread_id
to get the most recent created timestamp. */
/* Note that this assumes unique timestamp per post / thread_id */
select max( posts.created_at ) as lastpost,
thread_id
from posts
group by thread_id
) as lastpost_created_at
on threads.id = lastpost_created_at.thread_id
/* Now we join on to the posts table to get the associated user id */
/* (and any other fields you want from posts)*/
left join
posts
on threads.id = posts.thread_id
and posts.created_at = lastpost_created_at.lastpost
/* Then grab the user avatar etc */
left join
users
on posts.user_id = users.id
/* and finally get the total number of replies per thread */
left join
(
select thread_id,
count(*) as replies
from posts
group by thread_id
) as post_counts
on threads.id = post_counts.thread_id
One note: If two posts for a single thread have the exact same created_at
timestamp, this will result in a duplicate row for both posts.一个注意事项:如果单个线程的两个帖子具有完全相同的created_at
时间戳,这将导致两个帖子的行重复。
EDIT编辑
I've put together a query that only returns one result in the case of duplicate timestamps:我整理了一个查询,它在时间戳重复的情况下只返回一个结果:
select threads.id,
most_recent_post.created_at,
most_recent_post.user_id,
users.avatar,
post_counts.replies
from threads
left join
(
/* Get the most recent post per thread, ordered by created at and ID */
select di.id, di.user_id, di.created_at, di.thread_id
from (
select thread_id, max(created_at) AS created_at
from posts d
group by thread_id
) as dd
inner join
posts as di
on di.id = (
select id
from posts ds
where ds.thread_id = dd.thread_id
and ds.created_at = dd.created_at
order by id desc
limit 1
)
) as most_recent_post
on threads.id = most_recent_post.thread_id
/* Then grab the user avatar etc */
left join
users
on most_recent_post.user_id = users.id
/* and finally get the total number of replies per thread */
left join
(
select thread_id,
count(*) as replies
from posts
group by thread_id
) as post_counts
on threads.id = post_counts.thread_id
Updated SQLfiddle here .在这里更新了 SQLfiddle。 This uses a technique for Groupwise Maximum found here .这使用了此处找到的 Groupwise Maximum 的技术。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.