Вам не хватает столбца группировки, чтобы пометить чат между A и B как "принадлежащий друг другу" , не глядя, является ли A или B From
или To
.
Это ваш дизайн стола, который делает вещи сложными. Ниже моего предложения я добавлю несколько советов, как это можно сделать лучше:
Ваш макет для имитации вашей проблемы:
DECLARE @mockupTable TABLE(Id INT,[From] VARCHAR(100),[To] VARCHAR(100),[Text] VARCHAR(100),[Hour] TIME(0))
INSERT INTO @mockupTable VALUES
(1,'A','B','Msg_A_B1','00:01')
,(2,'A','B','Msg_A_B2','00:02')
,(3,'B','A','Msg_B_A1','00:03')
,(4,'A','B','Msg_A_B3','00:05')
,(5,'C','A','Msg_C_A1','00:11')
,(6,'A','C','Msg_A_C1','00:12')
,(7,'C','A','Msg_C_A2','00:14')
,(8,'D','B','Msg_D_B1','00:17');
- Запрос
WITH cte AS
(
SELECT t.*
,CONCAT(CASE WHEN t.[From]>t.[To] THEN t.[To] ELSE t.[From] END,'-',CASE WHEN t.[From]>t.[To] THEN t.[From] ELSE t.[To] END) AS ChatID
FROM @mockupTable t
)
,FindFirstAndLast AS
(
SELECT cte1.ChatID
,(SELECT TOP 1 Id FROM cte cte2 WHERE cte2.ChatID=cte1.ChatID ORDER BY cte2.[Hour] ASC) AS FirstId
,(SELECT TOP 1 Id FROM cte cte2 WHERE cte2.ChatID=cte1.ChatID ORDER BY cte2.[Hour] DESC) AS LastId
FROM cte cte1
GROUP BY cte1.ChatID
)
SELECT fal.ChatID
,tFirst.[From] AS FirstFrom
,tFirst.[To] AS FirstTo
,tFirst.[Hour] AS FirstHour
,tLast.[From] AS LastFrom
,tLast.[To] AS LastTo
,tLast.[Text] AS LastText
FROM FindFirstAndLast fal
INNER JOIN @mockupTable tFirst ON fal.FirstId=tFirst.Id
INNER JOIN @mockupTable tLast ON fal.LastId=tLast.Id;
Идея вкратце:
- Первый CTE создаст
ChatID
путем объединения From
и To
в отсортированном виде. При этом сообщение от A до B получит тот же ChatID, что и сообщение от B до A. - Второй CTE будет использовать коррелированный подзапрос, чтобы найти первый и последний идентификатор сообщения, сгруппированные дляранее вычисленный ChatID.
- В последнем SELECT эти идентификаторы сообщений будут использоваться для объединения соответствующих строк.
В результате вы получите все, что вам нужно. Это на вас, чтобы поставить его в необходимом формате:
+--------+-----------+---------+-----------+----------+--------+----------+
| ChatID | FirstFrom | FirstTo | FirstHour | LastFrom | LastTo | LastText |
+--------+-----------+---------+-----------+----------+--------+----------+
| A-B | A | B | 00:01:00 | A | B | Msg_A_B3 |
+--------+-----------+---------+-----------+----------+--------+----------+
| A-C | C | A | 00:11:00 | C | A | Msg_C_A2 |
+--------+-----------+---------+-----------+----------+--------+----------+
| B-D | D | B | 00:17:00 | D | B | Msg_D_B1 |
+--------+-----------+---------+-----------+----------+--------+----------+
Некоторые идеи о дизайне
Я бы использовал
- один стол
Person
дляваши собеседники. - вторая таблица
Chat
для чата с ChatID. - one
m:n
таблица сопоставления ChattingPerson
с JoinTime, ChatID и PersonID, оба в виде FK,Здесь вы можете установить временные метки, такие как LastAction или пометить статус (активный, ушел, ...) - еще одну таблицу
Message
для сообщений со временем, текстом и ChatPersonID как FK.
Ваши преимущества
Happy Coding: -)