4

我在stackoverflow中进行了搜索,但没有完全找到我的问题的确切答案,所以如果可以的话,请帮助我。

我“想要”构建一个这样的 SQL 语句:

SELECT
  @tax1 := (complicated calculation formula),
  @owe := (another complicated calculation formula),
  IF(@owe=0, 0,@tax1/@owe)
FROM ...

但是,在 MySQL 的关于user-defined variables的文档中,它建议不要这样说:

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

我的目标是避免复制和粘贴那些非常复杂的公式,因为它会妨碍可读性,如果公式每次都发生变化,我需要确保它在所有地方都发生变化 - 但我知道这样做,它会起作用美好的。

此外,我知道 ALIAS不起作用,因为别名仅在 GROUP BY、HAVING 和 ORDER 子句中起作用。

我阅读了其他一些帖子,首先进行子查询以计算@tax1 和@owe,然后使用另一个查询来组合结果。但我认为性能可能不如简单地复制和粘贴这些公式有效。

有没有人有任何建议他们会做什么?还是我坚持在可读性和性能之间进行选择?

提前致谢。

4

2 回答 2

2

是的,在没有用户变量的情况下在 SQL 中执行此操作的唯一方法是编写派生表子查询。然后您可以使用列别名来引用那些复杂表达式的结果:

SELECT tax1, owe, IF(owe=0, 0,tax1/owe) AS ratio
FROM (
  SELECT
    (complicated calculation formula) AS tax1,
    (another complicated calculation formula) AS owe
  FROM ...
) AS _sub

MySQL 在优化子查询方面存在一些问题,但派生表的情况并不是坏情况之一。

关于 MySQL 和子查询的警告是关于在 WHERE 子句的范围条件中使用子查询。MySQL 无法确定子查询是恒定的,即使没有必要,它也会将子查询重复地重新评估为依赖子查询。

于 2013-12-07T18:34:19.487 回答
0

我经常在选择语句中使用变量进行顺序评估、聚合、组统计和数据分类。

这是一个例子:

MySQL 列出每个类别的前 X 条记录,将每条记录与其先前的差异相结合

create table if not exists 
        closemovers engine=memory 
select 
          code 
        , date 
        , close 
        , rank 
        , prevclose 
        , sign 
        , cumm 
from 
        ( select 
                  `code` 
                , `date` 
                , `close` 
                , @rank := if( @code = code , @rank + 1 , 1) as rank 
                , @prevclose := if( @code = code , cast( @prclose as decimal(10,3) ), null) as prevclose 
                , if(@code = code, sign( @prclose - close), NULL) as sign 
                , @cumm := if(@code = code and @psign = sign(@prclose - close), @cumm + 1 , 1) as cumm
                , @psign := sign(@prclose - close) 
                , @code := code
                , @prclose := close 
        from 
            companyhistory 
        order by 
            code, date 
         ) as ranked 
 join 
        pricefeed 
                using (code) 
where 
        rank < 10 
        and sign is not null ;

我希望这能给你一个提示

于 2013-12-07T18:17:04.340 回答