我在AdventureWorks2012数据库上有以下查询
SELECT productid,
productname,
unitprice,
CASE
WHEN unitprice < 20.0 THEN 'LOW'
WHEN unitprice < 40.0 THEN 'MEDIUM'
WHEN unitprice >= 40.0 THEN 'HIGH'
END pricerange
FROM Production.Products
ORDER BY
CASE
WHEN pricerange < 'LOW' THEN 1
WHEN pricerange < 'MEDIUM' THEN 2
WHEN pricerange >= 'HIGH' THEN 3
END ASC
GO
ORDER BY
在SELECT
语句之后发生,但是无法访问pricerange列名?我假设SELECT
语句中的价格范围是在调用ORDER BY
后计算的?这是为什么?
答案 0 :(得分:3)
SQL是一种声明性语言,而不是命令式语言。执行顺序没有定义,并且并不总是相同。
无论如何,执行顺序并不重要。主要是范围 - 并且pricerange
不在该select语句中的任何范围内。不要考虑代码行出现的顺序(如在命令式编程中),您应该考虑每个表达式如何包装另一个表达式。
在这种情况下,你正在做这样的事情:
Select(OrderBy(From(Products), ...), ...)
你有两种解决方法 - 一种选择是按顺序使用与你在选择中使用的相同的情况(不要担心,引擎足够聪明,不能两次完成工作)。第二种是将查询包装在另一个执行实际排序的查询中:
select * from
(
SELECT productid,
productname,
unitprice,
CASE
WHEN unitprice < 20.0 THEN 'LOW'
WHEN unitprice < 40.0 THEN 'MEDIUM'
WHEN unitprice >= 40.0 THEN 'HIGH'
END pricerange
FROM Production.Products
)
ORDER BY
CASE
WHEN pricerange < 'LOW' THEN 1
WHEN pricerange < 'MEDIUM' THEN 2
WHEN pricerange >= 'HIGH' THEN 3
END ASC
但请记住,你在这里处理表达式树,而不是命令列表。您正在描述您想要的内容,而不是 它将如何执行。 如何是执行引擎的工作。
最后,执行引擎可能会为查询的两个变体制定相同的执行计划 - 它们并没有真正不同;虽然可能存在一些围绕NULL的边角情况,但我不确定。
答案 1 :(得分:3)
SQL Server解释了documentation中查询的逻辑处理顺序。
- FROM
- ON
- JOIN
- WHERE
- GROUP BY
- WITH CUBE或WITH ROLLUP
- HAVING
- 选择
- DISTINCT
- ORDER BY
- TOP
醇>
请注意,这是逻辑。实际上,这意味着在查询的编译阶段使用排序主要是为了确定引用引用的名称。另请注意,列表是关键字和子句的奇怪组合(ON
,WITH
,DISTINCT
和TOP
不是SQL子句。)
至于您的查询,pricerange
的定义由SELECT
中的逻辑决定。然后在ORDER BY
中进一步使用它来获得所需的顺序。这是处理的逻辑描述。
实际上,我希望SQL Server在扫描数据时计算pricerange
和排序优先级(SQL Server在读取数据时通过执行这些计算来优化这些计算)。 pricerange
计算进入最终结果集。订购部分仅由ORDER BY
使用。