4

I have this table on my database:

Message table

sentBy and sentTo are FK to User table.

On this table I have messages between users:

sentBy |  sentTo  |     dateSent     |     body
-------+----------+------------------+-----------------
  1    |    2     | 11/21/2010 10:00 | Hey!
-------+----------+------------------+-----------------
  2    |    1     | 11/21/2010 10:50 | Hi!
-------+----------+------------------+-----------------
  1    |    2     | 11/21/2010 10:51 | msg body 1
-------+----------+------------------+-----------------
  2    |    1     | 11/21/2010 11:05 | msg body 2
-------+----------+------------------+-----------------
  1    |    3     | 11/21/2010 11:51 | msg body 3
-------+----------+------------------+-----------------
  3    |    1     | 11/21/2010 12:05 | msg body 4
-------+----------+------------------+-----------------
  1    |    3     | 11/21/2010 12:16 | msg body 5
-------+----------+------------------+-----------------
  4    |    1     | 11/21/2010 12:25 | msg body 6
-------+----------+------------------+-----------------

I need to know the users with whom user 1 has talked and users that have talked with user 1. In this case, with users 2, 3 and 4 (note that user 4 has sent a message to user 1, but user 1 hasn't sent any message yet).

And the second question is: how can I get the last message with each user? I'm asking about to get the latest message sent to a user.

For example, if I'm asking about user 1, the latest message with user 2 is: msg body 2. And the latest message with user 3 is msg body 5.

How can I get that info in one SQL SELECT statement? Or maybe I will need two selects.

I'm trying to do something like WhatsApp. Where you have a chats screen with a list of users with whom I have talked (my first question), and the last message with them (my second question).

Maybe I can create another table named Conversation, move sentBy and sentTo to that table, and also last message with the date sent to it, but I think this can't be a good design.

The result for my two question is this:

sentBy |  sentTo  |     dateSent     |     body
-------+----------+------------------+-----------------
  2    |    1     | 11/21/2010 11:05 | msg body 2
-------+----------+------------------+-----------------
  1    |    3     | 11/21/2010 12:16 | msg body 5
-------+----------+------------------+-----------------
  4    |    1     | 11/21/2010 12:25 | msg body 6
-------+----------+------------------+-----------------
4

2 回答 2

4

以下查询将为您提供用户 1 的预期结果:

select m.* from messages m
join (
  select auser,withuser,max(datesent) datesent from (
    select sentby as auser,sentto as withuser,datesent from messages 
    union
    select sentto as auser,sentby as withuser,datesent from messages 
    ) as ud
  group by auser,withuser
  ) maxud 
  on (m.datesent=maxud.datesent and maxud.auser in (m.sentBy,m.sentTo))
where auser=1

不用说,您可以更改where子句中的条件以获得任何用户的相似结果。

但是,我的方法是创建一个视图,然后从中进行选择,如下所示:

create view conversation_stuff as
select m.sentBy,m.sentTo,m.dateSent,m.body,maxud.auser,maxud.withuser
from messages m
join (
  select auser,withuser,max(datesent) datesent from (
    select sentby as auser,sentto as withuser,datesent from messages 
    union
    select sentto as auser,sentby as withuser,datesent from messages 
    ) as ud
  group by auser,withuser
  ) maxud 
  on (m.datesent=maxud.datesent and maxud.auser in (m.sentBy,m.sentTo))

select sentBy,sentTo,dateSent,body from conversation_stuff where auser=1;

我猜这对其他用途也很有用。

编辑:更改userauser到处,让 sqlserver 停止抱怨避免[]...

于 2013-10-29T08:04:39.757 回答
0

选择在 sentBy 上过滤并按 sentTo 分组的最大 dateSent,然后将此结果连接回原始表。

编辑:我看到了问题。您想要用户发送和接收的消息中的最大消息吗?

SELECT
    Messages.*
FROM
    Messages
    INNER JOIN
    (
        SELECT
            CombinedKey,
            MAX(dateSent) AS dateSent
        FROM
        (
            SELECT
                CombinedKey = CASE WHEN sentBy > sentTo
                    THEN CAST(sentBy AS nvarchar(10)) + '_' 
                        + CAST(sentTo AS nvarchar(10))
                    ELSE CAST(sentTo AS nvarchar(10)) + '_'
                        + CAST(sentBy AS nvarchar(10))
                    END,
                MAX(dateSent) AS dateSent
            FROM
                Messages
            WHERE
                sentBy = @user
                OR sentTo = @user
            GROUP BY
                sentBy,
                sentTo
        ) AS MaxMessagesBoth
        GROUP BY
            CombinedKey
    ) AS MaxMessages    
        ON MaxMessages.CombinedKey = CASE WHEN sentBy > sentTo
            THEN CAST(sentBy AS nvarchar(10)) + '_'
                + CAST(sentTo AS nvarchar(10))
            ELSE CAST(sentTo AS nvarchar(10)) + '_'
                + CAST(sentBy AS nvarchar(10))
            END
        AND MaxMessages.dateSent = Messages.dateSent
于 2013-10-29T07:16:48.070 回答