为什么我不能使用CASE在ORDER BY中引用列别名?

Tim*_*ter 11 sql t-sql sql-server-2005 sql-order-by

对不起,如果这是重复,但我还没有找到一个.为什么我不能用在我的定义列别名SELECTORDER BY当我使用 CASE

考虑这个简单的查询:

SELECT NewValue=CASE WHEN Value IS NULL THEN '<Null-Value>' ELSE Value END
FROM dbo.TableA
ORDER BY CASE WHEN NewValue='<Null-Value>' THEN 1 ELSE 0 END
Run Code Online (Sandbox Code Playgroud)

结果是错误:

列名称"NewValue"无效

这是一个sql-fiddle.(替换为ORDER BY NewValue那个CASE WHEN...被注释掉的)

我知道在这种情况下我可以ORDER BY CASE WHEN Value IS NULL THEN 1 ELSE 0 END这里一样使用,但实际上查询更复杂,我希望尽可能保持可读性.我是否必须使用子查询或CTE,如果是这样,为什么会这样?

更新为Mikael Eriksson评论任何表达式与别名组合是不允许的.所以即使这个(毫无意义的查询)失败也是出于同样的原因:

SELECT '' As Empty
FROM dbo.TableA
ORDER BY Empty + ''
Run Code Online (Sandbox Code Playgroud)

结果:

列名称"空"无效.

因此,在一个ORDER BY和一个表达式中允许使用别名,但不能同时使用两者.为什么,实施起来太难了?由于我主要是一个程序员,我认为别名是变量,可以简单地用在表达式中.

Mik*_*ll' 6

这与SQL dbms如何解析模糊名称有关.

我还没有在SQL标准中追踪这种行为,但它似乎在各个平台上都是一致的.这是正在发生的事情.

create table test (
  col_1 integer,
  col_2 integer
);

insert into test (col_1, col_2) values 
(1, 3), 
(2, 2), 
(3, 1);
Run Code Online (Sandbox Code Playgroud)

别名"col_1"为"col_2",并使用ORDER BY子句中的别名.dbms将ORDER BY中的"col_2"解析为"col_1"的别名,并按"test"中的值进行排序."col_1".

select col_1 as col_2
from test
order by col_2;
Run Code Online (Sandbox Code Playgroud)
col_2
--
1
2
3

同样,别名"col_1"为"col_2",但在ORDER BY子句中使用表达式.dbms解析"col_2" 不是 "col_1"的别名,而是"test"."col_2"列.它按"test"中的值排序."col_2".

select col_1 as col_2
from test
order by (col_2 || '');
Run Code Online (Sandbox Code Playgroud)
col_2
--
3
2
1

因此,在您的情况下,您的查询失败,因为dbms想要将表达式中的"NewValue"解析为基表中的列名.但事实并非如此; 这是一个列别名.

PostgreSQL的

PostgreSQL在Sorting Rows部分中记录了此行为.他们陈述的理由是减少歧义.

请注意,输出列名称必须独立,也就是说,它不能在表达式中使用 - 例如,这正确:

SELECT a + b AS sum, c FROM table1 ORDER BY sum + c;          -- wrong
Run Code Online (Sandbox Code Playgroud)

这种限制是为了减少歧义.如果ORDER BY项是一个简单的名称,可以匹配输出列名称或表表达式中的列,则仍然存在歧义.在这种情况下使用输出列.如果您使用AS重命名输出列以匹配其他表列的名称,这只会造成混淆.

SQL Server 2008中的文档错误

一个稍微不同的问题,相对于在ORDER BY子句中的别名.

如果列名在SELECT列表中有别名,则只能在ORDER BY子句中使用别名.

除非我没有足够的咖啡因,否则这根本不是真的.此语句在SQL Server 2008和SQL Server 2012中按"test"."col_1"排序.

select col_1 as col_2
from test
order by col_1;
Run Code Online (Sandbox Code Playgroud)