MySQL用户变量和SUM函数

5

我想在SELECT查询中进行一些计算,使用用户变量来实现。这很好用,但是当我开始使用像 SUM 这样的函数从连接的表中收集数据时,就会出现问题。

以下是一个简化的示例:

SET @a = 1;

SELECT @a := SUM(1 + 1) AS sum, @a

结果:

+------+------+
| sum  | @a   |
+------+------+
|    2 |    1 |
+------+------+

我期望@a在这里是2。

另一个例子:

SELECT @b := SUM(1 + 1) AS sum, @b;
+------+------+
| 求和 | @b   |
+------+------+
|    2 | NULL |
+------+------+

现在是NULL,因为在查询之前没有设置@b。

似乎变量没有被SUM函数的结果覆盖。是否有修复这个问题的方法?


你真正想要实现什么。 - Ankit Sharma
@AnkitSharma:在SELECT查询中进行计算。因此,我需要在进一步的计算中使用例如SUM(1+1)的结果。我想把SUM(1+1)的结果存储在一个变量中,比如@a,然后在以后重复使用@a,而不是一遍又一遍地使用SUM(1+1) - Alec
@AnkitSharma:我不行。这只是一个简化的例子。SUM函数在查询语句中计算来自连接表的各种金额的总和。 - Alec
2个回答

7

正如文档所述:

通常来说,不要在同一个语句中为用户变量赋值并读取它的值。你可能会得到你预期的结果,但这并不是一定保证的。涉及用户变量的表达式的求值顺序是未定义的,并且可能会根据给定语句中包含的元素而发生变化;此外,这个顺序不能保证在MySQL服务器的不同版本之间是相同的。在 SELECT @a, @a:=@a+1, ... 中,你可能认为MySQL会首先计算 @a ,然后进行第二次赋值操作。然而,改变语句(例如添加GROUP BYHAVINGORDER BY子句)可能会导致MySQL选择不同的执行计划以更改求值顺序。

至于你问题的第二部分,你可以像这样在查询中初始化你的 @variable(子查询首先被求值):

SELECT @b := SUM(1 + 1) AS sum, @b FROM (SELECT @b:=0) b

不保证 :) 我重新发布的文档摘录解释了原因。只是不要在一个语句中这样做 - Pavel Veller
谢谢,我在文档中错过了那部分。我以为可以在查询本身中使用这些变量进行计算,以节省时间。但如果结果不一致,那就不是一个好的选择。由于我使用了很多不同的变量,这意味着也需要很多子查询,使它变得太复杂了。我想我只能坚持使用MySQL检索主要数据,并在之后使用PHP进行必要的计算了。 - Alec
实际上,doc语句表示不要在同一条语句中“赋值”并使用,并在进一步解释时指出这与“设置”并在同一语句中使用不同。换句话说,文档语句并不严格适用于您的问题,或者至少您可以通过在查询之前“分配”初始值来解决它,例如:SET @a = ...。实际问题是,MySQL在查询完成之前不会将聚合值分配给您的变量。只要您不将其用于聚合值,您的方法就可以正常工作。这就是解决方案有效的真正原因。 - Tom Haws

1

这与表达式评估有关。在您的情况下,您可以使用子查询 -

SET @a = 1;
SELECT sum, @a FROM
  (SELECT @a := SUM(1 + 1) AS sum, @a) t

+------+------+
| sum  | @a   |
+------+------+
|    2 |    2 |
+------+------+

更多信息 - 用户定义变量

通常情况下,您不应该在同一语句中为用户变量赋值并读取该值。您可能会得到预期的结果,但这并不是保证的。涉及用户变量的表达式的计算顺序是未定义的,并且可能会根据给定语句中包含的元素而发生更改;此外,这个顺序不能保证在 MySQL 服务器的不同版本之间相同。在 SELECT @a, @a:=@a+1, ... 中,您可能认为 MySQL 首先计算 @a,然后进行第二次赋值。但是,更改语句(例如添加 GROUP BY、HAVING 或 ORDER BY 子句)可能会导致 MySQL 选择具有不同计算顺序的执行计划。


如何获取状态变量的总和,例如Com_commit + Com_rollback? - SAGAR BHOOSHAN

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接