简体   繁体   English

MySQL 将选择子查询重构为连接

[英]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:我不确定我的解释是否正确,但您似乎想得到:

  • Every thread,每一个线程,
  • With the most recent post per thread,随着每个线程的最新帖子,
  • Including the user details (avatar etc) for who made the post包括发布者的用户详细信息(头像等)
  • And the total number of posts for each thread以及每个线程的帖子总数

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM