【问题标题】:MySQL merging queries correctlyMySQL正确合并查询
【发布时间】:2017-08-25 10:31:17
【问题描述】:

我有一个表格来存储包含以下列的消息:

+----+-----------+-----------+--------------+---------+------+---------------------+---------+
| ID | parent_id | author_id | recipient_id | subject | body | created             | is_read |
+----+-----------+-----------+--------------+---------+------+---------------------+---------+
| 1  | 0         | 51        | 52           | sub1    | bod1 | 2017-08-24 15:49:29 |    0    |
----------------------------------------------------------------------------------------------
| 2  | 1         | 52        | 51           | NULL    | bod2 | 2017-08-24 15:52:29 |    0    |
----------------------------------------------------------------------------------------------
| 3  | 1         | 51        | 52           | NULL    | bod3 | 2017-08-24 15:55:29 |    0    |
----------------------------------------------------------------------------------------------

我想从这张表中提取:

  • 每个“主题”的主题(主题的parent_id 为0,回复主题的值为NULL)
  • 线程中最新消息的创建日期
  • recipient_id等于当前user_id的线程中未读消息的数量

例如:

收件人 ID 51

+----+-----------+-----------+--------------+
| subject | last_message_date_time | unread |
+----+-----------+-----------+--------------+
| sub1    | 2017-08-24 15:55:29    | 1      |
---------------------------------------------

收件人 ID 52

+----+-----------+-----------+--------------+
| subject | last_message_date_time | unread |
+----+-----------+-----------+--------------+
| sub1    | 2017-08-24 15:55:29    | 2      |
---------------------------------------------

我已经编写了一些单独的查询,但我正在努力将它们与 JOINS(51 是当前用户 ID)放在一起:

1.当前用户的所有线程(线程的 parent_id 为 0)

SELECT m1.ID, m1.subject
FROM messages m1
WHERE (m1.author_id = 51 OR m1.recipient_id = 51)
    AND m1.parent_id = 0

2。线程中最后一条消息的时间戳

SELECT MAX(m2.created) as last_message_time_date
FROM messages m2
WHERE (author_id = 51 OR recipient_id = 51)

3。当前用户不是作者的未读消息数

SELECT COUNT(m3.ID) as unread
FROM messages m3
WHERE recipient_id = 51
    AND is_read = 0

我已经做到了:

SELECT m1.ID, m1.subject, MAX(m2.created), COUNT(m3.ID)
FROM messages m1
LEFT JOIN
    (SELECT created, parent_id
    FROM messages ) AS m2
    ON m1.ID = m2.parent_id
LEFT JOIN
    (SELECT ID, parent_id
    FROM messages 
    WHERE recipient_id = 51 AND is_read = 0) AS m3
    ON (m1.ID = m3.parent_id OR m1.ID = m3.ID)
WHERE (m1.author_id = 51 OR m1.recipient_id = 51)
    AND m1.parent_id = 0

我的问题是计数返回的值不正确(超过应有的值)。任何建议将不胜感激,非常感谢。

【问题讨论】:

  • 你能提供一些样本数据和想要的结果吗?
  • 当然,我已经用一些示例数据更新了我的问题。非常感谢。
  • 您也可以添加您想要的结果吗?你想从查询中得到什么结果
  • 哈,是的,只是在您评论时添加了这一点:)再次感谢
  • a) 如果一条消息“在一个线程中”,当有一个 parent_ids 到 ID 链时,你需要一个 CTE 或递归过程来处理这个查询。 b)“当前用户的线程(-启动消息)”是什么意思? 1 是 51 发送或接收的线程启动消息的 ID 和主题,我想这就是你的意思。 2是51发送或接收的最后一条消息的时间,不一定是任何线程中的最后一条消息。 3 是 51 收到的未读消息的计数,而不是 51 未发送的未读消息的计数。c) 所描述的或实际的查询都不会影响您应该编写的查询。

标签: mysql join left-join


【解决方案1】:

看来distinct 是答案:

SELECT m1.ID, m1.subject, m2.author_id, MAX(m2.created) as last_message_date_time, COUNT(distinct m3.ID) as unread
FROM messages m1 

LEFT JOIN messages m2 
    ON (m1.ID = m2.parent_id OR m1.ID = m2.ID)

LEFT JOIN 
    (
    SELECT ID, parent_id 
    FROM messages  
    WHERE is_read = 0 
        AND recipient_id = 51
    ) 
    AS m3 
    ON (m1.ID = m3.parent_id OR m1.ID = m3.ID)

WHERE (m1.author_id = 51 OR m1.recipient_id = 51) 
    AND m1.parent_id = 0

GROUP BY m1.ID

尽管如此,我们仍然愿意接受改进/建议 :)

【讨论】:

  • 此查询不返回您指定的列。你声称什么实际上是一个解决方案?这里 m2.author_id 每个组可以有多行,因此您需要对其进行分组或聚合它——阅读 ONLY_FULL_GROUP_BY。不在键上的两个左连接有时由聚合中的唯一值解决,但有时意味着您需要两个左连接的内连接。请阅读minimal reproducible example 并采取行动。例如,您的 MySQL 版本是什么?例如,您的限制是什么?
  • 感谢您的回复。我创建了一个 SQL Fiddle,希望能更好地展示我正在尝试做的事情以及到目前为止我是如何实现它的:sqlfiddle.com/#!9/7d3858/16 我已经删除了 author_id 部分,因为我意识到我不需要那个这个查询。
  • 感谢您的提琴和简化,我看到上面有评论。请编辑对您的问题的说明,而不是 cmets。请将小提琴代码和链接也放在您的问题中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-31
  • 2012-04-23
  • 1970-01-01
相关资源
最近更新 更多