如何更新我的查询以符合 sql_mode=only_full_group_by 启用? [复制]

Posted

技术标签:

【中文标题】如何更新我的查询以符合 sql_mode=only_full_group_by 启用? [复制]【英文标题】:How can I update my query to comply with sql_mode=only_full_group_by enabled? [duplicate] 【发布时间】:2019-08-03 11:22:45 【问题描述】:

在上次 mysql 更新后,我一直在寻找一种方法来纠正我的查询。我知道 Group By 列不是唯一的,但我不知道如何更新查询以符合严格的规则并仍然保留我正在寻找的结果。有人有建议吗?

SELECT 
    $SQLTable_Posts.`post_id`, 
    $SQLTable_Posts.`profile_id`, 
    $SQLTable_Posts.`post_title`, 
    $SQLTable_Posts.`post_slug`, 
    $SQLTable_Posts.`post_date`
FROM $SQLTable_Posts
WHERE $SQLTable_Posts.`post_date` > DATE_SUB(NOW(), INTERVAL 24 HOUR)
GROUP BY $SQLTable_Posts.`profile_id`
ORDER BY $SQLTable_Posts.`post_date` DESC

我想简单地返回每个配置文件发布的最新帖子。比如我的数据库是这样的;

<table><tbody><tr><th>post_id</th><th>profile_id post_date</th><th> </th></tr><tr><td>0001</td><td>0001</td><td>2019-03-12 00:00:00</td></tr><tr><td>0002</td><td>0002</td><td>2019-03-12 00:00:00</td></tr><tr><td>0003</td><td>0001</td><td>2019-03-12 01:00:00</td></tr><tr><td>0004</td><td>0004</td><td>2019-03-12 00:00:00</td></tr></tbody></table>

我希望结果返回这个;

<table><tbody><tr><th>post_id</th><th>profile_id post_date</th><th> </th></tr><tr><td>0003</td><td>0001</td><td>2019-03-12 01:00:00</td></tr><tr><td>0002</td><td>0002</td><td>2019-03-12 00:00:00</td></tr><tr><td>0004</td><td>0004</td><td>2019-03-12 00:00:00</td></tr></tbody></table>

【问题讨论】:

您要寻找的结果是什么?举个例子 您选择的每一列都应该被聚合(COUNT、SUM 等)或在您的 GROUP BY 子句中。 sql 如何知道 profile_id 0001 应该使用 post_id 0003 还是 0001 ?应该选择哪个? @kun-chan 我明白你的意思,感谢你让我思考。以前因为我按日期排序并按用户分组,它会抓取最新的,但是我没有看到任何解释如何告诉 sql 先抓取哪个文件的文档。 如果 profile_id 是主键,您不需要做任何特别的事情,因为所有其他列在功能上都依赖于它。 【参考方案1】:

我想简单地返回每个配置文件发布的最新帖子。

在不搞乱GROUP BY 的情况下做到这一点的一种方法是使用具有NOT EXISTS 条件的相关子查询,以确保选择的每条记录都是具有相同profile_id 的每组记录中的最新记录(我使用列post_date 对记录进行排序):

SELECT 
    `post_id`, 
    `profile_id`, 
    `post_title`, 
    `post_slug`, 
    `post_date`
FROM $SQLTable_Posts p
WHERE 
    `post_date` > DATE_SUB(NOW(), INTERVAL 24 HOUR)
    AND NOT EXISTS (
        SELECT 1
        FROM $SQLTable_Posts p1
        WHERE p1.`profile_id` = p.`profile_id` AND p1.`post_date` > p.`post_date`
    )
ORDER BY `post_date` DESC

注意:我简化了查询以删除冗长的表前缀,这里不需要(和/或可以用短表别名替换)。


如果您碰巧使用的是 MySQL 8.0,则直接使用 ROW_NUMBER()

SELECT *
FROM (
    SELECT 
        `post_id`, 
        `profile_id`, 
        `post_title`, 
        `post_slug`, 
        `post_date`,
        ROW_NUMBER() OVER(PARTITION BY `profile_id` ORDER BY `post_date` DESC) rn
    FROM $SQLTable_Posts p
    WHERE `post_date` > DATE_SUB(NOW(), INTERVAL 24 HOUR)
) x WHERE rn = 1
ORDER BY `post_date` DESC

【讨论】:

此解决方案非常有效,谢谢。但是,我只是注意到,如果有两个具有完全相同时间戳的帖子,它们都会出现。我们应该更新它以过滤这些。 @epool:好的,为此我们需要稍微调整一下查询。您使用的是哪个版本的查询,带有NOT EXISTS 的版本还是带有ROW_NUMBER() 的版本? 不存在的那个 OK 这样您就可以将子查询的WHERE 子句更改为:WHERE p1.profile_id = p.profile_id AND (p1.post_date > p.post_date OR (p1.post_date = p.post_date AND p1.post_id > p.post_id)。当有相同时间戳的帖子时,将选择id 最大的帖子。 完美无瑕!很好的解决方案。

以上是关于如何更新我的查询以符合 sql_mode=only_full_group_by 启用? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

与 sql_mode=only_full_group_by 不兼容的 MySQL 查询

如何在我的 Mac 上永久设置 SQL_MODE

遇到错误sql_mode = only_full_group_by,所以如何获得所需的结果

如何解决 laravel eloquent 中与 sql_mode=only_full_group_by 不兼容的问题?

在 MySql Godaddy VPS Cpanel 中使用 sql_mode=only_full_group_by 获取 MYSQL 错误

sql查询出现1055 this is incompatible with sql_mode=only_full_group_by