通过匹配SQL Server中的两列来对结果进行分组

时间:2015-06-30 18:45:34

标签: sql sql-server sql-server-2008-r2

我正在使用SQL Server 2008 R2。我有一个名为Messages的表,我在其中存储每个用户发送给其他用户的用户消息。表结构如下所示。

+--------+----------+-----------------+------------+
| Sender | Receiver |     Message     |    Date    |
+--------+----------+-----------------+------------+
| John   | Dennis   | How are you     | 2015-06-06 |
| John   | Dennis   | Hi              | 2015-06-05 |
| Tom    | John     | How much is it? | 2015-06-04 |
| Tom    | John     | Did you buy it? | 2015-06-03 |
| Robin  | Tom      | Hey man         | 2015-06-03 |
| Dennis | John     | What up         | 2015-06-02 |
| John   | Tom      | Call me         | 2015-06-01 |
+--------+----------+-----------------+------------+

我希望为每个对话获取所选用户的最新消息和其他参与者的姓名。举个例子,有三个对话。一个在“john-Dennis”之间,第二个在“John-Tom”之间,第三个在“Robin-Tom”之间。

如果我想获得用户john的对话,我希望获得最新的对话消息,其中包含对话中其他用户的名称。

上述情况的预期结果应该是这样的。

+-------------+-----------------+------------+
| Participant |     Message     |    Date    |
+-------------+-----------------+------------+
| Dennis      | How are you     | 2015-06-06 |
| Tom         | How much is it? | 2015-06-04 |
+-------------+-----------------+------------+

如何使用SQL Server中的SQL查询实现此目的。我好几天都在努力。请帮忙。提前致谢。

4 个答案:

答案 0 :(得分:3)

可以稍微压缩一下,但我已将其拆分为简单的步骤,希望能让它更容易理解。

-- Sample data from the question.
declare @msg table (Sender varchar(32), Receiver varchar(32), [Message] varchar(max), [Date] date);
insert @msg
    (Sender, Receiver, [Message], [Date])
values
    ('John','Dennis', 'How are you', '2015-06-06'),
    ('Dennis', 'John', 'Hi', '2015-06-05'),
    ('Tom', 'John', 'How much is it?', '2015-06-04'),
    ('Tom', 'John', 'Did you buy it?', '2015-06-03'),
    ('Robin', 'Tom', 'Hey man', '2015-06-03'),
    ('Dennis', 'John', 'What up', '2015-06-02'),
    ('John', 'Tom', 'Call me', '2015-06-01');

-- The name of the user whose conversations you want to find.
declare @UserName varchar(32) = 'John';

-- Step 1: Create columns [Participant1] and [Participant2] that will be the same for
--         each pair of users regardless of who's the sender and who the receiver.
with NameOrderCTE as
(
    select 
        Participant1 = case when Sender < Receiver then Sender else Receiver end,
        Participant2 = case when Sender < Receiver then Receiver else Sender end,
        *
    from
        @msg
),

-- Step 2: For each distinct pair of participants, create a [Sequence] number that 
--         puts the messages in reverse chronological order.
MessageSequenceCTE as
(
    select
        *,
        [Sequence] = row_number() over (partition by Participant1, Participant2 order by [Date] desc)
    from
        NameOrderCTE
)

-- Step 3: Get the most recent ([Sequence] = 1) messages for each conversation
--         involving the target user.
select
    Participant = case @UserName when Sender then Receiver else Sender end,
    [Message],
    [Date]
from
    MessageSequenceCTE
where
    @UserName in (Sender, Receiver) and
    [Sequence] = 1;

答案 1 :(得分:0)

尝试此查询

select a.Reciver as Participant,a.message,a.Date from message a
join(select sender,Receiver,max(date) from message where Sender = 'John'  group by sender,Receiver) b
on a.sender=b.sender and a.Receiver=b.Receiver and a.Date=b.date

答案 2 :(得分:0)

我认为它应该能满足您的需求:

SELECT a.Sender, a.Receiver, a.Message, a.[Date]
FROM 
(
   SELECT m.* , ROW_NUMBER() OVER (PARTITION BY 
   CASE 
     WHEN m.Sender = 'John' THEN 1 
     ELSE 2 
   END 
   ORDER BY [Date] DESC) AS rn
   FROM message m
   WHERE m.Sender = 'John' or m.Receiver ='John'
)a WHERE rn= 1

答案 3 :(得分:0)

根据我的理解,这可以胜任。虽然由于tempDb访问,它不是性能最佳的解决方案。

DECLARE @SelectedUser   NVARCHAR(100) = 'John'

SELECT TOP 1    Participant = Receiver,
                [Message],
                [Date]
INTO #tmp
FROM [Messages]
WHERE Sender = @SelectedUser
ORDER BY [Date]


SELECT *
FROM #tmp
UNION ALL
SELECT TOP 1 Participant = Sender,
       [Message],
       [Date]
FROM [Messages]
WHERE Receiver = @SelectedUser
ORDER BY [Date]