2

I am using mysql 8.0.23

I have three tables, chats, chat_users and chat_messages

I want to select the chat_id, the last message (with maximum createdAt date for a particular group. Said in other words, the message order by created_at desc within the group), from_user_id values for all the chats where user with id 1 is a member.

The tables sql and DDLs is are like below

create table chats
(
    id         int unsigned auto_increment primary key,
    created_at timestamp default CURRENT_TIMESTAMP not null
);

create table if not exists chat_users
(
    id      int unsigned auto_increment
        primary key,
    chat_id    int unsigned not null,
    user_id int unsigned not null,
    constraint chat_users_user_id_chat_id_unique
        unique (user_id, chat_id),
    constraint chat_users_chat_id_foreign
        foreign key (chat_id) references chats (id)
);

create index chat_users_chat_id_index
    on chat_users (chat_id);

create index chat_users_user_id_index
    on chat_users (user_id);


create table chat_messages
(
    id       int unsigned auto_increment primary key,
    chat_id  int unsigned                            not null,
    from_user_id int unsigned                            not null,
    content      varchar(500) collate utf8mb4_unicode_ci not null,
    created_at   timestamp default CURRENT_TIMESTAMP     not null    constraint chat_messages_chat_id_foreign
        foreign key (chat_id) references chats (id),
);

create index chat_messages_chat_id_index
    on chat_messages (chat_id);
    
create index chat_messages_from_user_id_index
    on chat_messages (from_user_id);

The query that I tried so far and is not working properly is


SET @userId = 1;
select
       c.id as chat_id,
       content,
       chm.from_user_id
from chat_users
         inner join chats c on chat_users.chat_id = c.id
         inner join chat_messages chm on c.id = chm.chat_id
where chat_users.user_id = @userId
group by c.id
order by c.id desc, max(chm.created_at) desc

My query above does not return the content field from the last created message, although I am trying to order by max(chm.created_at) desc. This order by after group by clause is executed after the grouping I think and not within the items from the group.. I know that I can probably select in the select statement the max date but I want to select last content value within the group not select max(ch.created_at) as last_created_at_msg_within_group

I don't know how to select the content field from the item that has the highest chm.created_at from within the group that I do by grouping with c.id

Example test data

chats

1 2021-07-23 20:51:01
2 2021-07-23 20:51:01
3 2021-07-23 20:51:01

chats_users

1 1 1
2 1 2
3 2 1 
4 2 2
5 3 1
6 3 2

chat_messages

1 1 1 lastmsg 2021-07-28 21:50:31
1 1 2 themsg  2021-07-23 20:51:01

The logic in this case should return

chat_id  content   from_user_id
1        lastmsg   1

PS: Before posting here I did my homework and studied similar questions in the forum, but they were trying to get last inserted row from a group and were not like mine.

Kristi Jorgji
  • 1,154
  • 1
  • 14
  • 39
  • 8.0.23. I will add this info in question as well – Kristi Jorgji Dec 06 '22 at 16:41
  • 2
    Can you add some data examples and expected result ? – Ergest Basha Dec 06 '22 at 16:50
  • [Tips for asking a good Structured Query Language (SQL) question](//meta.stackoverflow.com/questions/271055) – Akina Dec 06 '22 at 16:51
  • @ErgestBashaI added test case now in th quesiton – Kristi Jorgji Dec 06 '22 at 16:54
  • After you updated to 5.7 you need/should set SQL_MODE to the default which is defined by 8.0. Just to stop getting these kind of problems you should read about why you need to do that here: [MySQL implements detection of functional dependence. If the ONLY_FULL_GROUP_BY SQL mode is enabled](https://dev.mysql.com/doc/refman/8.0/en/group-by-handling.html) – Luuk Dec 06 '22 at 16:55
  • Someone closed my question as a duplicate but it is not a duplicate of the linked question... I read the other question already and is not even grouping the items – Kristi Jorgji Dec 06 '22 at 16:56
  • @KristiJorgji is this what you are looking for https://dbfiddle.uk/uBi7VXEH ? – Ergest Basha Dec 06 '22 at 17:07
  • @ErgestBasha yes the result is correct – Kristi Jorgji Dec 07 '22 at 10:47

1 Answers1

1

Here's what I came up with, for a solution for MySQL 8.0 with window functions:

select * from (
  select
      c.id as chat_id,
      content,
      chm.from_user_id,
      chm.created_at,
      row_number() over (partition by c.id order by chm.created_at desc) as rownum
  from chat_users
      inner join chats c on chat_users.chat_id = c.id
      inner join chat_messages chm on c.id = chm.chat_id
  where chat_users.user_id = @userId
) as t
where rownum = 1;
Bill Karwin
  • 538,548
  • 86
  • 673
  • 828
  • I tested this is working fine, thank you for the reply. I am not sure what is more performant this solution or one posted by @Ergest Basha as a comment reply using the `with` syntax. https://dbfiddle.uk/uBi7VXEH Have to test them with a large data set – Kristi Jorgji Dec 08 '22 at 14:32