How to get the latest message in each conversation of a certain user in SQL?

旧街凉风 提交于 2020-01-03 18:03:13

问题


I need to write a query that returns the latest message in a conversation between two users. I've included the schema and my (failed) attempts in this fiddle: http://sqlfiddle.com/#!15/322c3/11

I've been working around the problem for some time now but every time I run any of my ugly queries a sweet little kitten dies.

Any help would be much appreciated. Do it for the kittens.


回答1:


... the latest message in a conversation between two users.

Assuming the users with ID 1 and 3, like you did in the fiddle, we are interested in the message with the latest created_at and (sender_id, receiver_id) being (1,3) or (3,1).

You can use ad-hoc row types to make the syntax short:

SELECT * 
FROM   messages 
WHERE  (sender_id, receiver_id) IN ((1,3), (3,1))
ORDER  BY created_at DESC
LIMIT  1;

Or explicitly (and slightly faster, also easier to use with indexes):

SELECT * 
FROM   messages 
WHERE (sender_id = 1 AND receiver_id = 3 OR
       sender_id = 3 AND receiver_id = 1)
ORDER  BY created_at DESC
LIMIT  1;

For all conversations of a user

Added solution as per request in comment.

SELECT DISTINCT ON (user_id) *
FROM (
   SELECT 'out' AS type, id, receiver_id AS user_id, body, created_at
   FROM   messages 
   WHERE  sender_id = 1

   UNION  ALL
   SELECT 'in' AS type, id, sender_id AS user_id, body, created_at
   FROM   messages 
   WHERE  receiver_id = 1
   ) sub
ORDER  BY user_id, created_at DESC;

The approach here is to fold foreign sender / receiver into one column to simplify the extraction of the last row.

Detailed explanation for DISTINCT ON in this related answer:
Select first row in each GROUP BY group?

-> Updated SQLfiddle.

Also consider the improved and simplified test case in the fiddle.




回答2:


This provides the latest message between two users, regardless of message direction:

  SELECT Distinct mes.ID, sendu.Username AS Sender,
  recu.Username as Receiver, Body, maxSent as TimeSent

  FROM messages mes

  INNER JOIN 

  (
    SELECT One, Two, MAX(CREATED_AT) maxSent
    FROM
    (
      SELECT  'Sender' as type, Sender_ID AS One, receiver_id as Two,created_At
      FROM messages 

      UNION ALL

      SELECT 'Receiver' as type, receiver_id AS One, Sender_ID as Two ,created_At
      FROM messages 
    ) a

    Group By One,Two
  ) b

  ON mes.created_at = b.maxSent

  INNER JOIN users sendu
  ON sendu.ID = mes.Sender_ID

  INNER JOIN users recu
  ON recu.ID = mes.Receiver_ID

It does not separate 'conversations', but there is nothing to signify that. Perhaps if you also include a message header or title field this will be possible.




回答3:


SELECT * 
FROM messages 
WHERE (sender_id = 1 AND receiver_id = 2) 
   OR (sender_id = 2 AND receiver_id = 1) 
ORDER BY created_at DESC
LIMIT 1;



回答4:


Try this and see

SELECT  *
FROM    (SELECT * ,ROW_NUMBER() OVER(ORDER BY created_at DESC) as RowID
FROM   messages 
WHERE  (sender_id, receiver_id) IN ((1,3), (3,1))
    ) sub
WHERE   RowID = 1



回答5:


use this --> select * from messages order by created_at desc limit 1



来源:https://stackoverflow.com/questions/20856416/how-to-get-the-latest-message-in-each-conversation-of-a-certain-user-in-sql

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