SQL:从其他表中分组并反转结果

时间:2013-08-10 17:58:54

标签: mysql sql group-by sql-order-by greatest-n-per-group

我的SQL查询有问题 我有表message和表recipient

message

ID    author    date
--------------------
0        1      2013-07-08 05:38:47
1        1      2013-07-13 05:38:47
2        1      2013-07-15 05:38:47
3        1      2013-07-15 05:38:47
4        2      2013-07-17 05:38:47
5        1      2013-07-28 05:38:47

recipient

ID    m_id    recipient
--------------------
0        0      2
1        1      2
2        2      3
3        3      2
4        4      1
5        5      2

我需要从表message返回,并使用表recipient中的收件人列,其中最后一个日期位于message表中 我会试试这个

SELECT m.* 
FROM message as m
INNER JOIN recipient as r ON (m.ID = r.m_id)
WHERE m.author = 1
GROUP BY r.recipient
ORDER BY m.ID DESC

返回

ID    author    date
--------------------
2        1      2013-07-15 05:38:47
0        1      2013-07-08 05:38:47

但我需要

ID    author    date
--------------------
5        1      2013-07-28 05:38:47
2        1      2013-07-15 05:38:47

请帮助

我使用MySQL Server 5.1


我找到了解决问题的方法

SELECT m.* 
FROM (
SELECT * FROM recipient 
    WHERE 1=1
    ORDER BY recipient.ID DESC
) AS r
INNER JOIN message AS m ON (r.m_id = m.ID)
WHERE m.author = 1
GROUP BY r.recipient

只需反向表recipient

2 个答案:

答案 0 :(得分:2)

非常简单快速的 PostgreSQL DISTINCT ON - 非标准SQL,因此在每个RDBMS中都不可用。

问题没有提到它,但是从代码示例中得出它实际上是为每个收件人“strong> 寻找给定author 即可。

SELECT DISTINCT ON (r.recipient)  m.*
FROM   message   m
JOIN   recipient r ON r.m_id = m.id
WHERE  m.author = 1
ORDER  BY r.recipient, m.date DESC, r.m_id -- to break ties

详细信息以及多个SQL标准备选方案:
Select first row in each GROUP BY group?

使用基本标准SQL的另一种解决方案。适用于所有主要的RDBMS,包括 MySQL (因为已添加该标记):

SELECT m.* 
FROM   message   m
JOIN   recipient r ON r.m_id = m.id
WHERE  m.author = 1
AND NOT EXISTS (
   SELECT 1
   FROM   message   m1
   JOIN   recipient r1 ON r1.m_id = m1.id
   WHERE  r1.recipient = r.recipient 
   AND    m1.author = 1
   AND    m1.date > m.date
   )

只有具有最新日期的行才能通过NOT EXISTS反半连接。

答案 1 :(得分:1)

假设您正在使用SQL-Server,您可以使用ranking function之类的ROW_NUMBER

WITH CTE AS(
    SELECT m.*,
      RN=ROW_NUMBER()OVER(PARTITION BY r.recipient ORDER BY  m.date DESC)
    FROM message as m
    INNER JOIN recipient as r ON (m.ID = r.m_id)
    WHERE m.author = 1
)
SELECT * FROM CTE WHERE RN = 1

Demo