2017-09-01 133 views
1

語境:SQL:如何按兩列的唯一組合進行分組?

  • 的表message有列from_user_idto_user_id
  • 用戶應該看到的最後一條消息最近的談話顯示
  • 的對話由多條消息,有相同的組合用戶ID(用戶發送消息,用戶接收消息)

表內容:

+-------------------------------------------------+--------------+------------+ 
| text           | from_user_id | to_user_id | 
+-------------------------------------------------+--------------+------------+ 
| Hi there!          |   13 |   14 | <- Liara to Penelope 
| Oh hi, how are you?        |   14 |   13 | <- Penelope to Liara 
| Fine, thanks for asking. How are you?   |   13 |   14 | <- Liara to Penelope 
| Could not be better! How are things over there? |   14 |   13 | <- Penelope to Liara 
| Hi, I just spoke to Penelope!     |   13 |   15 | <- Liara to Zara 
| Oh you did? How is she?       |   15 |   13 | <- Zara to Liara 
| Liara told me you guys texted, how are things? |   15 |   14 | <- Zara to Penelope 
| Fine, she's good, too       |   14 |   15 | <- Penelope to Zara 
+-------------------------------------------------+--------------+------------+ 

我的嘗試是按from_user_idto_user_id,但我顯然得到一組用戶和另一組的消息的接收的消息的用戶發送。

​​

獲取我:

+-------------------------------+--------------+------------+---------------------+ 
| text       | from_user_id | to_user_id | created    | 
+-------------------------------+--------------+------------+---------------------+ 
| Oh you did? How is she?  |   15 |   13 | 2017-09-01 21:45:14 | <- received by Liara 
| Hi, I just spoke to Penelope! |   13 |   15 | 2017-09-01 21:44:51 | <- send by Liara 
| Oh hi, how are you?   |   14 |   13 | 2017-09-01 17:06:53 | 
| Hi there!      |   13 |   14 | 2017-09-01 17:06:29 | 
+-------------------------------+--------------+------------+---------------------+ 

雖然我想:

+-------------------------------+--------------+------------+---------------------+ 
| text       | from_user_id | to_user_id | created    | 
+-------------------------------+--------------+------------+---------------------+ 
| Oh you did? How is she?  |   15 |   13 | 2017-09-01 21:45:14 | <- Last message of conversation with Zara 
| Oh hi, how are you?   |   14 |   13 | 2017-09-01 17:06:53 | 
+-------------------------------+--------------+------------+---------------------+ 

我怎樣才能做到這一點?

編輯: 使用leastgreatest也不會導致所需的結果。 它確實將條目分組,但正如您在結果中看到的那樣,最後的消息不正確。做你想做什麼

+----+-------------------------------------------------+------+---------------------+--------------+------------+ 
| id | text           | read | created    | from_user_id | to_user_id | 
+----+-------------------------------------------------+------+---------------------+--------------+------------+ 
| 8 | Oh you did? How is she?       | No | 2017-09-01 21:45:14 |   15 |   13 | 
| 5 | Could not be better! How are things over there? | No | 2017-09-01 17:07:47 |   14 |   13 | 
+----+-------------------------------------------------+------+---------------------+--------------+------------+ 
+0

我們能至少適用於to_user_id和最大到from_user_id,然後將它們分組 –

+0

已經嘗試過,我編輯的嘗試的問題。分組工作正確,但我沒有收到最後一條消息 – StoryTeller

+0

爲什麼在最終結果中沒有「14,15」消息? –

回答

1

一種方法是使用相關子查詢,找到最小創建日期/時間匹配的對話:

SELECT m.* 
FROM message m 
WHERE 13 in (from_user_id, to_user_id) AND 
     m.created = (SELECT MAX(m2.created) 
        FROM message m2 
        WHERE (m2.from_user_id = m.from_user_id AND m2.to_user_id = m.to_user_id) OR 
         (m2.from_user_id = m.to_user_id AND m2.to_user_id = m.from_user_id) 
       ) 
ORDER BY m.created DESC 
+0

不應該是MAX(),因爲OP想要最新的消息? –

+0

是的,應該使用MAX(),但爲了公平起見,我在問題中提供了錯誤的期望結果。 – StoryTeller

0

我用GREATESTLEAST創造每一個GRP會話。然後對該grp進行排序並根據時間分配一個行號。

SQL DEMO

SELECT * 
FROM (
     SELECT LEAST(`from_user_id`, `to_user_id`) as L, 
       GREATEST(`from_user_id`, `to_user_id`) as G, 
       `text`, 
       CONCAT (LEAST(`from_user_id`, `to_user_id`), '-', GREATEST(`from_user_id`, `to_user_id`)) as grp, 
       @rn := if(@grp = CONCAT(LEAST(`from_user_id`, `to_user_id`), '-', GREATEST(`from_user_id`, `to_user_id`)), 
         @rn + 1, 
         if(@grp := CONCAT(LEAST(`from_user_id`, `to_user_id`), '-', GREATEST(`from_user_id`, `to_user_id`)), 1, 1) 
         ) as rn, 
       `time` 
     FROM Table1 
     CROSS JOIN (SELECT @rn := 0, @grp := '') as var 
     ORDER BY LEAST(`from_user_id`, `to_user_id`), 
       GREATEST(`from_user_id`, `to_user_id`), 
       `time` DESC 
    ) T 
WHERE rn = 1; 

輸出 enter image description here

編輯:在最後,你需要將13從對話篩選。

WHERE rn = 1 
    AND 13 IN (`L`, `G`); 
2

最後一次與#13的對話?在更新的DBMS中,您可以使用row_number()來查找這些數據庫。在MySQL中,您可以使用not exists來確保對話夥伴沒有更晚的帖子。順便提一下from_user_id + to_user_id - 13,你很容易找到合作伙伴的號碼。 (和比較兩個記錄時,你可以使用from_user_id + to_user_id。)

select text, from_user_id, to_user_id, created 
from message m1 
where 13 in (from_user_id, to_user_id) 
and not exists 
(
    select * 
    from message m2 
    where 13 in (m2.from_user_id, m2.to_user_id) 
    and m2.from_user_id + m2.to_user_id = m1.from_user_id + m1.to_user_id 
    and m2.created > m1.created 
); 
+0

你**不能**比較id總和,'13 + 5 = 8 + 10',但是是不同的對話 –

+0

@Juan Carlos Oropeza:你錯過了'WHERE'子句。你的第二對不包含13,因此不會被選中。 –