0

我对 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语句中的 pricerange 是在调用之后计算ORDER BY的?为什么是这样?

4

2 回答 2

3

SQL 是一种声明性语言,而不是命令性语言。执行顺序没有定义,也不总是相同的。

无论如何,执行顺序并不重要。主要的一点是范围- 并且pricerange不在该 select 语句中的任何范围内。与其考虑代码行出现的顺序(如在命令式编程中),不如考虑每个表达式如何包装另一个表达式。

在这种情况下,你正在做这样的事情:

Select(OrderBy(From(Products), ...), ...)

您有两种解决方法 - 一种选择是在 order by 中使用与您在 select 中使用的相同的大小写(不用担心,引擎足够聪明,不会做两次工作)。第二个是将您的查询包装在另一个执行实际排序的查询中:

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 周围可能存在一些极端情况,但我不确定。

于 2015-08-07T14:54:47.887 回答
3

SQL Server在文档中解释了查询的逻辑处理顺序。

  1. 加入
  2. 在哪里
  3. 通过...分组
  4. WITH CUBE 或 WITH ROLLUP
  5. 拥有
  6. 选择
  7. 清楚的
  8. 订购方式
  9. 最佳

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

至于您的查询, 的定义pricerangeSELECT. 然后将其进一步用于ORDER BY获得您想要的排序。这是处理的逻辑描述。

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

于 2015-08-07T14:56:49.663 回答