我总是被我应该如何处理这些问题所困扰,哪种解决方案更好。我想示例代码应该更好地解释它。
假设我们有一个包含3列的表:
我想在Value
列上获取基本列和一些计算,但每个计算都基于前一个,换句话说就是这样:
SELECT
*,
Value + 10 AS NewValue1,
Value / NewValue1 AS SomeOtherValue,
(Value + NewValue1 + SomeOtherValue) / 10 AS YetAnotherValue
FROM
MyTable
WHERE
Name LIKE "A%"
显然这不起作用。 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
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
但哪一种是解决问题的正确方法,还是只是“更好”?
P.S。是的,我知道“更好”甚至“好”的解决方案在SQL中并不总是相同的,并且取决于很多因素。
答案 0 :(得分:1)
我已经厌倦了两种变体中的许多不同的计算组合。它们总是生成相同的执行计划,因此可以假设性能方面没有差异。从代码可用性的角度来看,第一种方法显然更好,因为代码更具可读性和紧凑性。
答案 1 :(得分:1)
没有"对"写这种查询的方法。与大多数数据库一样,SQL Server(MySQL是一个值得注意的例外)不会为每个子查询创建中间表。相反,它会优化整个查询,并经常将表达式的所有计算移动到单个处理节点中。
无法在同一级别重复使用列别名的原因是ANSI标准定义。特别是,标准中没有任何内容指定单个表达式的评估顺序。在不知道顺序的情况下,SQL无法保证在评估之前定义变量。
我经常编写多级查询 - 使用子查询或CTE - 使查询更具可读性和可维护性。但话又说回来,我也会将逻辑从一个变量复制到另一个变量,因为它是有利的。在我看来,这是查询的作者需要决定的事情,考虑到查询是否是需要维护的系统的代码的一部分,本地编码标准,查询是否可能被修改和类似的考虑。