通过匹配 SQL 服务器中的两列对结果进行分组
Group result by matching two columns in SQL Server
我正在使用 SQL Server 2008 R2。我有一个名为 Messages
的 table,我在其中存储每个用户发送给其他用户的用户消息。 table 结构如下。
+--------+----------+-----------------+------------+
| 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 服务器中使用 SQL 查询来实现此目的。几天来我一直在努力解决这个问题。请帮忙。提前致谢。
试试这个查询
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
我认为它应该能满足您的需求 :
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
根据我的理解,这可以完成工作。尽管由于访问 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]
可以稍微压缩一下,但我已将其分成简单的步骤,希望能更容易理解。
-- 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;
我正在使用 SQL Server 2008 R2。我有一个名为 Messages
的 table,我在其中存储每个用户发送给其他用户的用户消息。 table 结构如下。
+--------+----------+-----------------+------------+
| 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 服务器中使用 SQL 查询来实现此目的。几天来我一直在努力解决这个问题。请帮忙。提前致谢。
试试这个查询
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
我认为它应该能满足您的需求 :
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
根据我的理解,这可以完成工作。尽管由于访问 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]
可以稍微压缩一下,但我已将其分成简单的步骤,希望能更容易理解。
-- 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;