SELECT 查询不返回没有 ORDER BY 子句的结果

Posted

技术标签:

【中文标题】SELECT 查询不返回没有 ORDER BY 子句的结果【英文标题】:SELECT query returns no result without ORDER BY clause 【发布时间】:2014-05-20 17:19:43 【问题描述】:

我有这个问题:

SELECT  `Stocks`.`id` AS  `Stocks.id` ,  `Locations`.`id` AS  `Locations.id`  
FROM  `rowiusnew`.`c_stocks` AS  `Stocks` 
LEFT JOIN  `rowiusnew`.`g_locations` AS  `Locations` ON ( `Locations`.`ref_id` =  `Stocks`.`id` AND `Locations`.`ref_type` =  'stock' ) 
GROUP BY  `Stocks`.`id` 
HAVING `Locations.id` IS NOT NULL

这会返回 0 个结果。

当我添加时

ORDER BY Locations.id

对于完全相同的查询,我正确地得到 3 个结果。 值得注意的是:当我丢弃 GROUP BY 子句时,我得到相同的 3 个结果。分组对于带有附加连接的完整查询是必要的;这是演示问题的简化版。

我的问题是:为什么我没有得到原始查询的结果?

请注意,JOIN ON 子句中有两个条件。更改或删除大括号或更改这些条件的顺序不会改变结果。

通常,您会怀疑g_locations 中的字段id 有时为NULL,因此ORDER BY 子句使正确引用的结果显示在组数据集的“顶部”。不是这种情况; id 字段已正确设置为主键字段并使用 auto_increment。

EXPLAIN 语句显示在我实际得到结果的情况下使用文件排序而不是索引。原始查询如下所示:

修改后的工作查询如下所示:

以下是表格定义:

CREATE TABLE IF NOT EXISTS `c_stocks` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`id_stock_type` int(10) unsigned DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`locality` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `StockType_idx` (`id_stock_type`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `g_locations` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`ref_type` enum('stock','object','branch') DEFAULT NULL,
`ref_id` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `UniqueLocation` (`ref_type`,`ref_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

ref_id 字段包含我在此定义中省略的长注释。

【问题讨论】:

尝试在sqlfiddle.com中提供一些数据 好点。这让我意识到我在 mysql 5.6.12 中遇到了一个错误。 【参考方案1】:

在 SQLFiddle.com 和我的第二台计算机上无法重现该错误后,我意识到一定存在错误。

确实,我使用的 5.6.12 版本存在这个错误:

某些使用 GROUP BY 的 LEFT JOIN 查询可能会返回不正确的结果。 (错误 #68897、错误 #16620047)

查看 MySQL 5.6.13 的变更日志:http://dev.mysql.com/doc/relnotes/mysql/5.6/en/news-5-6-13.html

升级到 5.6.17 解决了我的问题。我没有得到我期望的结果,独立于 ORDER 子句和聚合函数。

【讨论】:

【参考方案2】:

删除

having locations.id is not null

改为使用

where locations.id is not null

locations.id 不为 null 对分组来说不是问题 - 您根本不希望包含它们。

另外,您需要对locations.id 做一些事情,因为它不在group by 子句中。你想要“最大”位置.id 吗?

所以您的查询现在变为:

SELECT  `Stocks`.`id` AS  `Stocks.id` ,  max(`Locations`.`id`) AS  `Locations.id`  
FROM  `rowiusnew`.`c_stocks` AS  `Stocks` 
LEFT JOIN  `rowiusnew`.`g_locations` AS  `Locations` ON ( `Locations`.`ref_id` =  `Stocks`.`id` AND `Locations`.`ref_type` =  'stock' ) 
WHERE `Locations.id` IS NOT NULL
GROUP BY  `Stocks`.`id` 

进行这些更改,它应该更适合您。

仅供参考:我认为通过输入 order by 子句,您可以让引擎猜测您想要的位置。id,否则它没有任何线索。在 MYSQL 之外的其他东西中,它根本不会运行。

【讨论】:

确实,聚合函数会输出正确的结果。但是,您对 MySQL 必须猜测的断言是错误的。请注意,ref_id 和 ref_type 上有一个 UNIQUE 索引,它将最大匹配行数限制为 1。

以上是关于SELECT 查询不返回没有 ORDER BY 子句的结果的主要内容,如果未能解决你的问题,请参考以下文章

在 group by 中使用 datetime 日期并在单个 SELECT 中使用 order by 与使用子查询

当子查询内存在ORDER BY 字句时查询会报错

order by中用子查询排序

在SQL Server的子查询视图内联函数等数据库对象中,不应该单独使用ORDER BY语句

oracle子查询

子查询中的 Order By 的 SQL 错误