Sql 重复操作与多级查询

Sql 重复操作与多级查询,sql,sql-server,Sql,Sql Server,我总是为我应该如何处理这些问题而烦恼,哪种解决方案更好。我想示例代码应该更好地解释它 假设我们有一个包含3列的表: (int)Id (nvarchar)名称 (int)值 我想得到基本列加上值列上的一些计算,但每一个计算都是基于前一个,换句话说,类似这样: SELECT *, Value + 10 AS NewValue1, Value / NewValue1 AS SomeOtherValue, (Value + NewValue1 + SomeOtherV

我总是为我应该如何处理这些问题而烦恼,哪种解决方案更好。我想示例代码应该更好地解释它

假设我们有一个包含3列的表:

  • (int)Id
  • (nvarchar)名称
  • (int)值
我想得到基本列加上
列上的一些计算,但每一个计算都是基于前一个,换句话说,类似这样:

SELECT
    *,
    Value + 10 AS NewValue1,
    Value / NewValue1 AS SomeOtherValue,
    (Value + NewValue1 + SomeOtherValue) / 10 AS YetAnotherValue
FROM
    MyTable
WHERE
    Name LIKE "A%"
SELECT
    t2.*,
    (t2.Value + t2.NewValue1 + t2.SomeOtherValue) / 10 AS YetAnotherValue
FROM
(
    SELECT
        t1.*,
        t1.Value / t1.NewValue1 AS SomeOtherValue
    FROM
    (
        SELECT
            *,
            Value + 10 AS NewValue1
        FROM
            MyTable
        WHERE
            Name LIKE "A%"
    ) t1
) t2
显然,这是行不通的
NewValue1
SomeOtherValue
YetAnotherValue
在查询中处于同一级别,因此它们在计算中不能相互引用

SELECT
    *,
    Value + 10 AS NewValue1,
    Value / (Value + 10) AS SomeOtherValue,
    (Value + (Value + 10) + (Value / (Value + 10))) / 10 AS YetAnotherValue
FROM
    MyTable
WHERE
    Name LIKE "A%"
我知道有两种编写查询的方法,可以得到所需的结果。第一个是重复计算

SELECT
    *,
    Value + 10 AS NewValue1,
    Value / (Value + 10) AS SomeOtherValue,
    (Value + (Value + 10) + (Value / (Value + 10))) / 10 AS YetAnotherValue
FROM
    MyTable
WHERE
    Name LIKE "A%"
另一个涉及构造如下所示的多级查询:

SELECT
    *,
    Value + 10 AS NewValue1,
    Value / NewValue1 AS SomeOtherValue,
    (Value + NewValue1 + SomeOtherValue) / 10 AS YetAnotherValue
FROM
    MyTable
WHERE
    Name LIKE "A%"
SELECT
    t2.*,
    (t2.Value + t2.NewValue1 + t2.SomeOtherValue) / 10 AS YetAnotherValue
FROM
(
    SELECT
        t1.*,
        t1.Value / t1.NewValue1 AS SomeOtherValue
    FROM
    (
        SELECT
            *,
            Value + 10 AS NewValue1
        FROM
            MyTable
        WHERE
            Name LIKE "A%"
    ) t1
) t2
但是,哪一种方法是解决问题的正确方法,还是仅仅是“更好”


是的,我知道“更好”甚至“好”的解决方案在SQL中并不总是一样的,这取决于许多因素。

我已经厌倦了这两种变体中的许多不同计算组合。它们总是生成相同的执行计划,因此可以假设性能方面没有差异。从代码可用性的角度来看,第一种方法显然更好,因为代码更具可读性和紧凑性。

编写此类查询没有“正确”的方法。与大多数数据库一样(MySQL是一个显著的例外),SQL Server不会为每个子查询创建中间表。相反,它将查询作为一个整体进行优化,并经常将表达式的所有计算移动到单个处理节点中

列别名不能在同一级别重复使用的原因在于ANSI标准定义。特别是,标准中没有任何内容指定单个表达式的求值顺序。如果不知道顺序,SQL无法保证在求值之前定义变量


我经常编写多级查询——使用子查询或CTE——以使查询更具可读性和可维护性。不过,我还要把逻辑从一个变量复制到另一个变量,因为这是权宜之计。在我看来,这是查询作者需要决定的事情,考虑到查询是否是需要维护的系统代码的一部分,本地编码标准,查询是否可能被修改,和类似的考虑。

显然,第一种方法是更好的方法,因为它不需要通过子查询重新计算临时表。此外,这里有两个子查询,而第一个子查询没有。这是一个有趣的见解。检查执行计划是否有差异,如果没有,请坚持使用可读性更强的执行计划。我之所以接受这一点,是因为我提到了相同的执行计划。然而,应该注意的是,即使查询产生相同的执行计划,执行时间也可能以可重复的方式不同(即,一个查询总是比另一个查询执行得稍快)。这些差异通常很小,但如果查询真的很复杂,它可能会更明显。