2013-03-24 52 views
2

我需要特定的SQL查詢來選擇用戶收件箱的最後10個對話。 收件箱僅向每個用戶顯示對話(線索) - 它會選擇對話中的最後一條消息並將其顯示在收件箱中。查詢以獲取用戶收件箱的最後對話

已編輯。

預期結果:從10 latest conversations的每一箇中提取latest message。 Facebook以同樣的方式顯示最新對話

還有一個問題。如何使pagination顯示下一頁中之前最近一次對話的後10條最新消息?

數據庫悄悄話的樣子:

| id | user_id | recipient_id | text 
| 1 | 2  | 3   | Hi John! 
| 2 | 3  | 2   | Hi Tom! 
| 3 | 2  | 3   | How are you? 
| 4 | 3  | 2   | Thanks, good! You? 
+1

你能提供一個你期待的結果輸出嗎?在上面的例子中,我假設user_id 2只有1條記錄,對他來說有最新的消息:'謝謝,好!您?' – Akash 2013-03-24 08:03:47

+0

已添加!感謝您的幫助;)是的你是對的,我只需要這次對話的最後一條消息,+9更多來自其他最新對話的俚語消息... – Gediminas 2013-03-24 11:57:41

回答

1

按我的理解,你需要得到每個用戶爲基礎的談話最新消息(最後10個最新的談話)

更新:我已經修改了查詢來獲取該latest_conversation_message_id爲每個用戶通話

下面的查詢獲取詳細信息user_id = 2,您可以修改,users.id = 2得到它的任何其他用戶

SQLFiddle,希望這能解決你的目的

SELECT 
    user_id, 
    users.name, 
    users2.name as sent_from_or_sent_to, 
    subquery.text as latest_message_of_conversation 
FROM 
    users 
    JOIN 
    (
    SELECT 
     text, 
     row_number() OVER (PARTITION BY user_id + recipient_id ORDER BY id DESC) AS row_num, 
     user_id, 
     recipient_id, 
     id 
    FROM 
     private_messages 
    GROUP BY 
     id, 
     recipient_id, 
     user_id, 
     text 
    ) AS subquery ON ((subquery.user_id = users.id OR subquery.recipient_id = users.id) AND row_num = 1) 
    JOIN users as users2 ON (users2.id = CASE WHEN users.id = subquery.user_id THEN subquery.recipient_id ELSE subquery.user_id END) 
WHERE 
    users.id = 2 
ORDER BY 
    subquery.id DESC 
LIMIT 10 

信息:查詢得到與任何其他用戶每次談話的最新消息,如果user_id 2,將消息發送到user_id 3,那也顯示,作爲它表示對話的開始。顯示與任何其他用戶的每次對話的最新消息

+0

謝謝!這對我來說有點太高級了:)也許有一種方法可以將它轉換爲只接收private_messages id而不是通過包含用戶表? (我需要從每10個最新的對話中提取最新的消息ID)謝謝! – Gediminas 2013-03-24 11:53:31

+0

我已經更新了答案,請chk現在.. – Akash 2013-03-24 12:14:52

+0

謝謝阿卡什!你的答案提供了我一直期待的結果,並且你已經做了一個查詢來獲取用戶參數。你能把你的代碼從小提琴粘貼到你的答案嗎?這對其他人會有用! – Gediminas 2013-03-24 12:38:07

0

您的WHERE子句

ORDER BY "ColumnName" [ASC, DESC] 

UNION Description at W3Schools它結合了這2個語句的結果後粘貼。

SELECT "ColumnName" FROM "TableName" 
UNION 
SELECT "ColumnName" FROM "TableName" 
+0

謝謝!但我需要以某種方式限制消息。我只需要向每個用戶提供最後一條消息。與每個用戶的對話可以有100個或更多的消息來代替。 – Gediminas 2013-03-24 07:59:20

+0

正如你在你的陳述中所寫的那樣,你使用ORDER columnName的LIMIT 10可以將結果ASC或DESC。 – Mikatsu 2013-03-24 08:02:45

1

要解決pg中的groupwise-max,可以使用DISTINCT ON。就像這樣:

SELECT 
DISTINCT ON(pm.user_id) 
    pm.user_id, 
    pm.text 
FROM 
    private_messages AS pm 
WHERE pm.recipient_id= <my user id> 
ORDER BY pm.user_id, pm.id DESC; 

http://sqlfiddle.com/#!12/4021d/19

要獲取最新的X但是我們將有子查詢中使用它:

SELECT 
q.user_id, 
q.id, 
q.text 
FROM 
(
SELECT 
DISTINCT ON(pm.user_id) 
    pm.user_id, 
pm.id, 
    pm.text 
FROM 
    private_messages AS pm 
WHERE pm.recipient_id=2 
ORDER BY pm.user_id, pm.id DESC 
) AS q 
ORDER BY q.id DESC 
LIMIT 10; 

http://sqlfiddle.com/#!12/4021d/28

要獲取發出和收到的線程:

SELECT 
q.user_id, 
q.recipient_id, 
q.id, 
    q.text 
FROM 
(
SELECT 
DISTINCT ON(pm.user_id,pm.recipient_id) 
    pm.user_id, 
    pm.recipient_id, 
pm.id, 
    pm.text 
FROM 
    private_messages AS pm 
WHERE pm.recipient_id=2 OR pm.user_id=2 
ORDER BY pm.user_id,pm.recipient_id, pm.id DESC 
) AS q 
ORDER BY q.id DESC 
LIMIT 10; 

http://sqlfiddle.com/#!12/4021d/42

+1

this將不包括由發件人發起的對話 – Akash 2013-03-24 12:17:51

+0

@Akash你是對的,我更新了可以做到這一點的查詢。 – 2013-03-24 12:28:50

+0

感謝您的簡單和乾淨的查詢。它給出的不是我想要的,但仍然是工作 - 選擇每個對話的最後兩條消息。有時可以向用戶顯示他們已經回覆的消息是有用的。 – Gediminas 2013-03-24 12:39:47

0

對於大型數據集我想你可能想嘗試運行兩個語句,然後鞏固成果,作爲(USER_ID和id)或(recipient_id和id)索引掃描應該是非常有效的獲得每種類型的最近10次會話。

with sent_messages as (
    SELECT * 
    FROM  private_messages 
    WHERE user_id = my_user_id 
    ORDER BY id desc 
    LIMIT 10), 
received_messages as ( SELECT * 
    FROM  private_messages 
    WHERE recipient_id = my_user_id 
    ORDER BY id desc 
    LIMIT 10), 
all_messages as (
    select * 
    from sent_messages 
    union all 
    select * 
    from received_messages) 
select * 
from  all_messages 
order by id desc 
limit 10 

編輯:其實另一個查詢值得嘗試的可能是:

select * 
from private_messages 
where id in (
     select id 
     from (
      SELECT id 
      FROM  private_messages 
      WHERE user_id = my_user_id 
      ORDER BY id desc 
      LIMIT 10 
      union all 
      SELECT id 
      FROM  private_messages 
      WHERE recipient_id = my_user_id 
      ORDER BY id desc 
      LIMIT 10) all_ids 
      order by id desc 
      limit 10) last_ten_ids 
order by id desc 

這可能是9.2+,其中單獨的指標可以被用來獲取ID的更好,或者在情況下,最最近檢索的數量非常大。儘管如此,還是有點不清楚。如果有疑問,我會去爲前一個版本。

+0

看起來非常有效。但是我的兩個查詢都出現了一些錯誤:「在union上或附近出現語法錯誤」。 我該如何轉換查詢以從兩個查詢中只獲取10個最新對話,而不是彼此? – Gediminas 2013-03-24 11:45:23

+0

@Lucas postgres似乎並不喜歡按順序排列,或者查詢中的限制被聯合使用,所以我將它們分解爲公用表表達式。似乎很好:http:// sqlfiddle。 com /#!12/91dac/6 – 2013-03-24 12:06:44

+0

出現了問題 - 它會從每次對話中選擇兩個或更多消息,我已經得到了我需要的查詢。 – Gediminas 2013-03-24 12:46:39