我的数据库中有这个表:
sentBy
和sentTo
是FK到User
表。
在这张桌子上,我有用户之间的消息:
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
-------+----------+------------------+-----------------
我需要知道用户1与之交谈的用户以及与用户1交谈的用户。在这种情况下,对于用户2,3和4(请注意,用户4已向用户1发送了消息,但用户1尚未发送任何消息)。
第二个问题是:我如何才能获得每个用户的最后一条消息?我要求将最新消息发送给用户。
例如,如果我询问用户1,则用户2的最新消息是:msg body 2.而用户3的最新消息是msg body 5.
如何在一个SQL SELECT语句中获取该信息?或者我可能需要两个选择。
我正在尝试做一些像 WhatsApp 这样的事情。你有一个聊天屏幕,其中包含我与之交谈的用户列表(我的第一个问题),以及带有它们的最后一条消息(我的第二个问题)。
也许我可以创建另一个名为Conversation
的表,将sentBy
和sentTo
移动到该表,并且还会发送包含发送日期的消息,但我认为这不可能是一个很好的设计。
我的两个问题的结果是:
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
-------+----------+------------------+-----------------
答案 0 :(得分: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;
我猜这也可能对其他用途有用。
编辑:将user
更改为auser
,sqlserver停止抱怨和以避免[]
...
答案 1 :(得分: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