【问题标题】:A SQL Join returns duplicate data and messes with SQL querySQL 连接返回重复数据并与 SQL 查询混淆
【发布时间】:2014-04-18 14:57:39
【问题描述】:

我一直在逐步测试我最近开发的公告板。我在我的 SQL 查询中遇到了一个小错误。

SELECT `user`.avatar, `user`.username, `user`.id AS user_id, `post`.title, 
       `post`.id, `post`.date AS post_date, `comment`.date AS last_comment_date
FROM `post`
INNER JOIN `user` ON `post`.user_id = `user`.id
LEFT JOIN `comment` ON `post`.id = `comment`.post_id
WHERE `post`.category_id = 1
ORDER BY IFNULL(`last_comment_date`, `post_date`) DESC;

会产生类似的东西;

我碰巧知道这是什么原因。 MySQL 将所有 cmets 与其 post 连接起来,换句话说,它是一对多的关系,一个 post 可以有多个 cmets。这会产生分页问题,​​因为前十个帖子可能相同,具体取决于它是否有十个 cmets。我碰巧只需要comment 表中的最新评论日期。

我遇到了几个解决方案。

  • post.id 分组,但在行分组后不能按顺序执行。

  • 检索整个结果集并通过 PHP 对我需要的内容进行排序。使用这种方法,我的性能可能会受到很大影响。

  • 执行多个查询,但这不是个好主意。

  • 执行子查询,但我不知道这是否是一种不好的做法。

最好的做法是什么?如果是一对多关系,是否有办法阻止 MySQL 在连接中返回重复数据?

编辑 1

正如@Zane 所问,这个 SQL 查询...

SELECT `user`.avatar, `user`.username, `user`.id AS user_id, `post`.title, `post`.id, 
`post`.date AS post_date, MAX(`comment`.date) 
FROM `post` 
INNER JOIN `user` ON `post`.user_id = `user`.id 
LEFT JOIN `comment` ON `post`.id = `comment`.post_id 
WHERE `post`.category_id = 1 
GROUP BY `post`.id 
ORDER BY IFNULL(MAX(`comment`.date), `post_date`) DESC

产生;

这似乎正是我想要的。如果帖子有 cmets (或发布日期),则帖子将按最新评论日期排序。我也可以将它与分页 LIMITS 一起使用,而无需任何预处理。我还需要IFNULL 吗?我想是的。

EDiT 2

还有一个缺陷。如果帖子的 last_comment_date 为 NULL,则无法正确排序。如果你参考下图。你可以看到 last_comment_date 就在那里,即使应该发生了碰撞。

请忽略下面的内容。


编辑 3

这就是我想要的。

【问题讨论】:

  • 我知道这并不能直接解决您的问题,但为了将来参考,请勿使用保留名称,如 user 作为列名。
  • 您是否尝试过使用MAX() 作为评论日期,然后使用Group by 其他列?
  • +1 啊谢谢您的评论!我没有意识到这是一个保留关键字。 D:这就是为什么我打字时它的颜色编码。不管是否需要,我都计划稍微修改一下结构。
  • @Zane 你确定user 是保留关键字吗?
  • @Zane 请参考我上面的编辑。你是这样的意思吗?我还需要ifnull吗?我想我会的,因为不是每个帖子都会有评论,谢谢!我也相信阿比克。当我在 SQL 编辑器中输入它时,它会用颜色编码。

标签: php mysql sql join duplicates


【解决方案1】:

我认为 GROUP BY 是您的最佳选择。只需按除 comment.date 之外的所有选定列进行分组,并使用 MAX 函数获取最新的评论日期,如下所示:

SELECT
    `user`.avatar,
    `user`.username,
    `user`.id AS user_id,
    `post`.title,
    `post`.id,
    `post`.date AS post_date,
    MAX(`comment`.date) AS last_comment_date

FROM
    `post` INNER JOIN `user` ON `post`.user_id = `user`.id
    LEFT JOIN `comment` ON `post`.id = `comment`.post_id

WHERE
    `post`.category_id = 1

GROUP BY
    `user`.avatar,
    `user`.username,
    `user`.id,
    `post`.title,
    `post`.id,
    `post`.date

ORDER BY
    IFNULL(`last_comment_date`, `post_date`) DESC;

【讨论】:

  • 取决于您想要实现的目标。现在我只使用了你原来的想法,它按最后评论日期排序,但如果这是 null 使用发布日期,实际上这就是你的截图显示的内容。也许您想首先按最后评论日期(最后为空)排序,然后按发布日期排序?
  • 参见上面的编辑#3,将其与编辑#2中的图像进行比较。这就是我要的。这可以用 SQL 实现吗?我想我已经尝试按最后评论日期排序,然后发布日期。
  • 我想了解为什么帖子 id 2 排在 1 之前而不是 3 之前?对于(1 和 2)来说,最后一个动作(发布日期或最后评论日期)都在 3 的发布之前。所以两者都应该在 3 之前或之后。对我来说,现在似乎没有订单。
  • 更正:为什么帖子 id 3 排在 1 之前而不是 2 之前?
  • 如果你看,id 为 2 的帖子的评论日期比 id 为 3 的帖子的date 更新。即使它是在“2014-03-13 13: 49:46” 2 的 id 有一条评论日期为“2014-03-13 01:09:57”。哦,等等,我的坏!我忘了实际评论 id 为 2 的帖子。现在它比 id 为 3 的帖子更新。感谢您的所有帮助! =)
猜你喜欢
  • 2010-09-30
  • 2015-04-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-19
  • 2014-10-08
  • 1970-01-01
  • 2014-09-09
相关资源
最近更新 更多