mysql: select the last 10 messages and for each message the last 3 replies

纵然是瞬间 提交于 2019-12-01 12:58:26

A working example:

EDIT - (see revision for earlier query)

Full table creation and explain plan
Note: The table "datetable" just contains all dates for about 10 years. It is used just to generate rows.

drop table if exists messages;
create table messages (
   message_id int primary key, reply_to int, createdate datetime, index(reply_to));

insert into messages 
select @n:=@n+1, floor((100000 - @n) / 10), a.thedate
from (select @n:=0) n
cross join datetable a
cross join datetable b
limit 1000000;

The above generates 1m messages, and some valid replies. The query:

select m1.message_id, m1.reply_to, m1.createdate, N.N, r.*
from
(
    select m.*, (
         select group_concat(r.message_id order by createdate)
          from messages r
        where r.reply_to = m.message_id) replies
     from messages m
     order by m.message_id
    limit 10
) m1
inner join ( # this union-all query controls how many replies per message
    select 1 N union all
     select 2 union all
     select 3) N
  on (m1.replies is null and N=1) or (N <= length(m1.replies)-length(replace(m1.replies,',','')))
left join messages r
  on r.message_id = substring_index(substring_index(m1.replies, ',', N), ',', -1)

Time: 0.078 sec

Explain plan

id     select_type         table        type      possible_keys    key      key_len ref                rows    Extra
1      PRIMARY             <derived4>   ALL      (NULL)            (NULL)   (NULL)  (NULL)             3    
1      PRIMARY             <derived2>   ALL      (NULL)            (NULL)   (NULL)  (NULL)             10      Using where
1      PRIMARY             r            eq_ref   PRIMARY           PRIMARY  4       func               1    
4      DERIVED             (NULL)       (NULL)   (NULL)            (NULL)   (NULL)  (NULL)             (NULL)  No tables used
5      UNION               (NULL)       (NULL)   (NULL)            (NULL)   (NULL)  (NULL)             (NULL)  No tables used
6      UNION               (NULL)       (NULL)   (NULL)            (NULL)   (NULL)  (NULL)             (NULL)  No tables used
(NULL) UNION RESULT        <union4,5,6> ALL      (NULL)            (NULL)   (NULL)  (NULL)             (NULL)    
2      DERIVED             m            index    (NULL)            PRIMARY  4       (NULL)             1000301    
3      DEPENDENT SUBQUERY  r            ref      reply_to          reply_to 5       test.m.message_id  5       Using where

I would suggest you build your extra table, and make it work with as many steps as necessary. Sometimes to visualize the answer you need extra steps. At the end, you can compile the SQL into one nested statement.

RichardTheKiwi

Note: This answer provides useful information for comparison for OMG's comments, so even if it needs to be deleted, please leave it up for a while.

OMG: Check the pairing of mysql and "greatest-n-per-group" tags -- the request is very common. OMG: Then visit the questions and courteously inform if not answer.

I followed your instructions OMG, and this is what I came up with from
https://stackoverflow.com/questions/tagged/greatest-n-per-group+mysql

  1. SQL - Give me 3 hits for each type only
  2. mySQL Returning the top 5 of each category
  3. MySQL SELECT n records base on GROUP BY

You may have misunderstood the question because of the 3 that looked most similar form the first page of results (2 of which are my answers), the questions deal with a single dimension (top n per category) for the entire table. The solutions offered invariably row_number ALL records in the table ordered by category.

Compare that to the optimized answer provided for this question for the problem domain top-n-category -> top-m-per-category and you will realize that this question is a different one.

There is no need to visit the questions and courteously inform if not answer because

  1. The answer to those questions are valid
  2. The answer to this question is valid
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!