没有ORDER BY子句,SELECT查询不返回任何结果

时间:2014-05-20 17:19:43

标签: mysql group-by sql-order-by filesort

我有这个问题:

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子句中有两个条件。更改或删除大括号或更改这些条件的顺序不会改变结果。

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

EXPLAIN语句显示在实际获得结果的情况下,使用filesort而不是索引。原始查询如下所示:

original query

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

http://i.stack.imgur.com/6Pk6w.png

以下是表格定义:

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字段包含我在此定义中省略的长注释。

2 个答案:

答案 0 :(得分:1)

在无法在SQLFiddle.com和我的第二台计算机上重现错误之后,我意识到必须涉及到一个错误。

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

  

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

请参阅MySQL 5.6.13的更改日志:http://dev.mysql.com/doc/relnotes/mysql/5.6/en/news-5-6-13.html

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

答案 1 :(得分:0)

删除

having locations.id is not null

改为使用

where locations.id is not null

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

此外,您需要对locations.id执行某些操作,因为它不在group by子句中。你想要“max”locations.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子句,你允许引擎猜测你想要的locations.id,否则它没有任何线索。在MYSQL以外的东西中,它根本不会运行。