CASE语句何时评估?

时间:2015-08-07 14:45:29

标签: sql tsql ssms adventureworks

我在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 BYSELECT语句之后发生,但是无法访问pricerange列名?我假设SELECT语句中的价格范围是在调用ORDER BY后计算的?这是为什么?

2 个答案:

答案 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中查询的逻辑处理顺序。

  
      
  1. FROM
  2.   
  3. ON
  4.   
  5. JOIN
  6.   
  7. WHERE
  8.   
  9. GROUP BY
  10.   
  11. WITH CUBE或WITH ROLLUP
  12.   
  13. HAVING
  14.   
  15. 选择
  16.   
  17. DISTINCT
  18.   
  19. ORDER BY
  20.   
  21. TOP
  22.   

请注意,这是逻辑。实际上,这意味着在查询的编译阶段使用排序主要是为了确定引用引用的名称。另请注意,列表是关键字和子句的奇怪组合(ONWITHDISTINCTTOP不是SQL子句。)

至于您的查询,pricerange的定义由SELECT中的逻辑决定。然后在ORDER BY中进一步使用它来获得所需的顺序。这是处理的逻辑描述。

实际上,我希望SQL Server在扫描数据时计算pricerange和排序优先级(SQL Server在读取数据时通过执行这些计算来优化这些计算)。 pricerange计算进入最终结果集。订购部分仅由ORDER BY使用。