【问题标题】:Define a variable within select and use it within the same select在 select 中定义一个变量并在同一个 select 中使用它
【发布时间】:2013-05-18 21:44:38
【问题描述】:

有没有可能做这样的事情?

SELECT 
    @z:=SUM(item),
    2*@z
FROM
    TableA;

我总是得到第二列的 NULL。奇怪的是,在做类似的事情时

SELECT 
    @z:=someProcedure(item),
    2*@z
FROM
    TableA;

一切都按预期进行。为什么?

【问题讨论】:

  • 我非常希望@z:=someProcedure(item), 2*@z 在上面工作只是一个快乐的巧合。

标签: mysql mysql-variables


【解决方案1】:

我们不能在同一个 select 语句中安全地定义和使用变量。最好的方法是不要在 SELECT 查询中使用 SET 变量。替代查询是

select temp.z,temp.z*2
    from (SELECT sum(item) As `z`
          FROM TableA
         )temp;

【讨论】:

    【解决方案2】:
    mysql> select @z := sum(5), if(@z := sum(5), 2*@z, 0) ;
    +--------------+------------------------------+
    | @z := sum(5) | if(@z := sum(5), 2*@z, null) |
    +--------------+------------------------------+
    |            5 |                           10 |
    +--------------+------------------------------+
    

    我相信将2*@z 包装在if 语句中将确保在额外计算之前执行sum

    【讨论】:

    • 如果您在使用@z 的两个地方执行相同的计算,那么分配给@z 有什么意义?!
    • 包装在 if 语句中确实会强制(我的版本)在进入语句的 then 部分之前执行该语句。
    【解决方案3】:

    适用于 mysql 5.5

    select @code:=sum(2), 2*@code
    
    +---------------+---------+
    | @code:=sum(2) | 2*@code |
    +---------------+---------+
    |             2 |       4 |
    +---------------+---------+
    

    【讨论】:

    • 不,这在我的 MySQL 5.6 设置中不起作用;第二列在第一次调用时产生 NULL,如果再次运行,则返回 2 倍 上一个结果,这可能会让人误以为它确实有效。现在,有趣的是,select @code:=2, 2*@codeselect @code:=rand(), 2*@code; do 都在同一个安装中工作(今天)。因此,鉴于文档(请参阅 Gordon 的回答),我不会依赖它来返回一些定义的结果。
    【解决方案4】:

    MySQL documentation 对此非常清楚:

    作为一般规则,您永远不应该为用户变量赋值 并读取同一语句中的值。你可能会得到 您期望的结果,但这不能保证。的顺序 涉及用户变量的表达式的评估是未定义的,并且 可能会根据给定语句中包含的元素而更改; 另外,这个顺序不保证在 MySQL 服务器的版本。在 SELECT @a, @a:=@a+1, ... 中,您可能 认为 MySQL 会先评估 @a 然后做一个赋值 第二。但是,更改语句(例如,通过添加 GROUP BY、HAVING 或 ORDER BY 子句)可能会导致 MySQL 选择一个 具有不同评估顺序的执行计划。

    你可以使用子查询做你想做的事:

    select @z, @z*2
    from (SELECT @z:=sum(item)
          FROM TableA
         ) t;
    

    【讨论】:

    • 查询比较复杂,不想再添加子查询。为什么它与程序一起工作?在过程中使用变量比使用过程两次要快得多。所以我就是不明白,为什么这也不适用于 sum(item)。
    • 但是子选择是选择语句的一部分,所以你的建议也是未定义的。
    • @philipxy 。 . .子查询在外部查询之前运行,因此定义了排序。
    • @GordonLinoff 这不受文档支持,与a bug report reply specifically about it 明确矛盾。读取和写入同一变量的 SELECT 语句文本具有未定义的行为。如果您能提供一些相反的证据,我将非常高兴。实证检验不算作证据。仅仅因为每个人都这样做,而且实际上现在应该这样做,因为风险是值得的,并没有定义它。
    • @philipxy 。 . .错误报告与 子查询 中定义的变量无关。而且,虽然文档没有我想要的那么明确,但 SQL 要求在 SELECT 之前评估 FROM 子句,因此在子查询中定义的变量应该是安全的。
    猜你喜欢
    • 2012-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-28
    • 1970-01-01
    • 1970-01-01
    • 2022-12-10
    相关资源
    最近更新 更多