了解Sql Server查询 - ORDER BY子句中的CASE

Nic*_*ndo 7 sql t-sql sql-server

我正试图在列表中使用a 中的put CASE语句,并找到一些我不理解的奇怪行为.这是一些代码:ORDER BYDISTINCTSELECT

select distinct Requester, ISO_ID as ISO, (ISO_ID - 5 + 50) AS 'someNum', BU
from LoanerHeader order by
CASE WHEN 'a' = 'b' then Requester
when 'b' = 'c' then BU
else ISO_ID
end
Run Code Online (Sandbox Code Playgroud)

这有效.但是,如果我将第4行更改为when 'b' = 'b' then BU:

select distinct Requester, ISO_ID as ISO, (ISO_ID - 5 + 50) AS 'someNum', BU
from LoanerHeader order by
CASE WHEN 'a' = 'b' then Requester
when 'b' = 'b' then BU
else ISO_ID
end
Run Code Online (Sandbox Code Playgroud)

它打破了错误:

如果指定了SELECT DISTINCT,则ORDER BY项必须出现在选择列表中.

什么时候BU显然在选择列表中.更奇怪的是当我将代码更改为:

select distinct Requester, ISO_ID as ISO, (ISO_ID - 5 + 50) AS 'someNum', BU
from LoanerHeader order by
CASE WHEN 'a' = 'b' then Requester
when 'b' = 'b' then BU
else BU   --change is here
end
Run Code Online (Sandbox Code Playgroud)

它又有效了!这怎么有意义呢?有人能帮我把这个脑袋包裹起来吗?

Mar*_*ith 7

规则CASE是结果应该转换为具有最高优先级的分支的数据类型.

对于第一个查询,它使用矛盾检测,只生成一个ISO_ID直接排序的计划.这已经是数字,所以不需要隐式转换,因此匹配选择列表中的表达式没有问题.

对于第二个查询,它可以在编译时再次确定它需要ORDER BY BU.除了它实际上需要ORDER BY CAST(BU AS NUMERIC)由于上述.这意味着它需要ORDER BY一个计算表达式,不匹配SELECT列表中的任何内容.因此问题.

您的第三个查询从中删除了更高优先级的表达式,CASE从而消除了对隐式强制转换的需要(因此需要按计算表达式排序).

由于计算表达式完全取决于SELECT DISTINCT列表中的列,但您可以按如下方式重写第二个查询.

;WITH CTE AS
(
SELECT DISTINCT Requester,
                ISO_ID              AS ISO,
                ( ISO_ID - 5 + 50 ) AS 'someNum',
                BU
FROM   LoanerHeader
)
SELECT *
FROM CTE
ORDER  BY CASE
            WHEN 'a' = 'b' THEN Requester
            WHEN 'b' = 'b' THEN BU
            ELSE ISO
          END
Run Code Online (Sandbox Code Playgroud)