【问题标题】:SQL: group by from other table and invert resultSQL:从其他表分组并反转结果
【发布时间】:2013-08-10 17:58:54
【问题描述】:

我的 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 服务器 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

【问题讨论】:

  • 你使用的是什么 rdbms?
  • 为什么要为一位作者返回两行?
  • GROUP BY 应该做什么?
  • 缺失:您的 RDBMS 和版本。表定义包括 NOT NULL、FK 和 PK 约束。如何断绝关系?如何处理丢失的收件人(如果可能)?
  • 你的测试用例多处矛盾。我假设消息2 2 3 中的这一行应为2 2 1,根据您的描述,结果应为4 2 2013-07-17 05:38:475 1 2013-07-28 05:38:47

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


【解决方案1】:

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

问题没有提到它,但从代码示例中得出,它实际上是在为每个收件人寻找具有“最后日期”的行对于给定的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 反半连接。

【讨论】:

    【解决方案2】:

    假设您使用的是 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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-09-13
      • 2020-10-21
      • 2019-05-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多