时间:2015-12-13 14:22:53

标签: mysql sql-order-by limit mariadb having

TL; DR

始终使用group by

问题描述

我在使用MariaDB中的selecthavingorder by的{​​{1}}查询时遇到问题:

limit

Defintions

假设我们有两行简单的mysql Ver 15.1 Distrib 10.1.9-MariaDB, for Linux (x86_64) using readline 5.1表:

test

我们还有一个简单的代理函数DROP TABLE IF EXISTS `test`; CREATE TABLE `test` ( `weight` INT(11) NOT NULL, `x` INT(11) NOT NULL ) COLLATE='utf8_general_ci' ENGINE=InnoDB ; INSERT INTO `test` (`weight`, `x`) VALUES (1, 33); INSERT INTO `test` (`weight`, `x`) VALUES (1, 44); ,它只通过第一个参数:

TestProxy

使用DROP FUNCTION IF EXISTS `TestProxy`; delimiter // CREATE FUNCTION `TestProxy`( x double(9,6) ) RETURNS double(8,2) NO SQL BEGIN RETURN x; END// delimiter ;

进行查询

如果我使用where条件运行以下选择查询,我希望得到一个行:

where

使用SELECT `test`.weight, `test`.x FROM `test` WHERE 35 <= TestProxy(`test`.x) ORDER BY weight ASC LIMIT 0, 1;

的非工作查询

但是,如果我将having替换为where,我会在MariaDB中设置。在MySQL中,我期望得到一个行:

having

使用SELECT `test`.weight, `test`.x FROM `test` HAVING 35 <= TestProxy(`test`.x) ORDER BY weight ASC LIMIT 0, 1; 但没有having函数的工作查询

此外,当我使用TestProxy并再次将having替换为TestProxy时,我希望得到一个行:

test.x

使用SELECT `test`.weight, `test`.x FROM `test` HAVING 35 <= `test`.x ORDER BY weight ASC LIMIT 0, 1; 进行查询但使用having

包装

最后,当我使用select打包查询并将select移到包装器时,我希望得到一行行:

limit

但是,这个查询非常慢。

使用SELECT * FROM ( SELECT `test`.weight, `test`.x FROM `test` HAVING 35 <= TestProxy(`test`.x) ORDER BY weight ASC ) as table1 LIMIT 0, 1; 进行查询,具体取决于having

在阅读并分析了@slaakso和@ gordon-linoff的答案之后,我进一步调查了它,简化了问题,并意识到只有在第一次出现在将返回的结果集上时才会返回一行在应用order by之前。

因此,一个行会产生以下查询:

limit

以下查询将以设置:

SELECT
    33 = TestProxy(`test`.x) as tp
FROM `test`
HAVING tp
ORDER BY x ASC
LIMIT 0, 1;

使用SELECT 33 = TestProxy(`test`.x) as tp FROM `test` HAVING tp ORDER BY x DESC LIMIT 0, 1; having

进行查询

如果我添加group by,则在MariaDB中按预期方式返回一个行:

group by

摘要

有人可以解释为什么MariaDB存在不一致之处?我错过了什么,或者是MariaDB中的错误? 我想这与优化查询有关,但我不知道如何检查它。

有没有人建议如何修复它?这显然是一个简化的例子;我的复杂查询需要SELECT 33 = TestProxy(`test`.x) as tp FROM `test` GROUP BY tp HAVING tp ORDER BY x DESC LIMIT 0, 1;

2 个答案:

答案 0 :(得分:1)

一种可能性非常微妙。这是&#34;工作的查询&#34;在MySQL但没有&#34;#34;工作&#34;在MariaDB:

SELECT `test`.weight, `test`.x
FROM `test`
HAVING 35 <= TestProxy(`test`.x)
ORDER BY weight ASC
LIMIT 0, 1;

我怀疑使用不在select列表中的表达式,以及没有having的{​​{1}}。

documentation明确指出:

  

标准SQL的另一个MySQL扩展允许引用   选择列表中的别名表达式的HAVING子句。

查询中没有任何内容是group by列表中的别名表达式。

由于select在没有having的情况下使用,我的猜测很混乱。因为表达式不在group by中,所以可能MySQL / MariaDB决定在一个不确定的行上评估它一次,而不是每行一次。两个数据库之间的结果差异可能仅仅是由于选择了行。

在任何情况下,在任何其他数据库中,没有select的{​​{1}}通常看起来很尴尬。 <{1}}没有having且不允许使用聚合函数。

答案 1 :(得分:0)

WHERE和HAVING不可互换。 HAVING只应用作GROUP BY的条件。 MySQL / MariaDB在如何编写SQL方面非常宽松,因此不会发出警告/错误,有时您可能会得到意想不到的结果。

在你的情况下,函数调用似乎在ORDER BY / LIMIT组合之后执行,导致函数只接收值为33的行。