用HAVING查询,你能解释一下这种行为吗?

时间:2011-08-19 10:19:24

标签: mysql

你能解释一下这种行为吗?

CREATE TABLE test( a INT );

INSERT INTO test VALUES (21), (22), (23), (24), (25);

SELECT @row := @row + 1 AS r, a FROM test
  JOIN ( SELECT @row := 0 ) AS init
  ORDER BY a;

----------
| r | a  |
----------
| 1 | 21 |
| 2 | 22 |
| 3 | 23 |
| 4 | 24 |
| 5 | 25 |
----------

SELECT @row := @row + 1 AS r, a FROM test
  JOIN ( SELECT @row := 0 ) AS init
  HAVING r = 3
  ORDER BY a;

----------
| r | a  |
----------
| 4 | 23 |
----------

4 个答案:

答案 0 :(得分:3)

符合http://dev.mysql.com/doc/refman/5.0/en/user-variables.html

在SELECT语句中,仅在发送到客户端时评估每个select表达式。这意味着在HAVING,GROUP BY或ORDER BY子句中,引用在select表达式列表中赋值的变量不能按预期工作:

mysql> SELECT (@aa:=id) AS a, (@aa+3) AS b FROM tbl_name HAVING b=5;

HAVING子句中对b的引用是指选择列表中使用@aa的表达式的别名。这不能按预期工作:@aa包含上一个选定行的id值,而不是当前行。

所以你有前一行的数据。

答案 1 :(得分:2)

我无法解释这种行为(错误?),但这里有一个替代解决方案,可以像你期望的那样工作:

SELECT * FROM
    (SELECT @row := @row + 1 AS r, a FROM test
      JOIN ( SELECT @row := 0 ) AS init
      ORDER BY a) as tmp
WHERE tmp.r = 3

答案 2 :(得分:2)

HAVING子句的评估导致初始计算@row := @row + 1 AS r

1st Pass: r = 1, fail.
2nd Pass: r = 2, fail.
3rd Pass: r = 3, success.

然后,当将结果发送到客户端@row := @row + 1 AS r再次进行评估,并且@row的值变为4,以便得到结果:

r = 4, a = 23.

答案 3 :(得分:0)

这看起来像bug,但是如果你在C ++中检查增量的实现,你会看到表达式后的postfix ++操作更新变量。对于存储过程,它可以是正确的行为。我认为就是这种情况。