2013-03-24 57 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