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

时间:2014-09-10 11:12:51

标签: sql tsql sql-server-2005 sql-order-by

很抱歉,如果这个重复,但我还没找到。当我使用SELECT时,为什么我无法使用ORDER BYCASE中定义的列别名?

考虑这个简单的查询:

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

结果是错误:

  

无效的列名称'NewValue'

Here's a sql-fiddle.(将ORDER BY NewValue替换为已注释掉的CASE WHEN...

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

更新,因为Mikael Eriksson已将任何表达式与别名结合使用。所以即使这个(毫无意义的查询)失败也是出于同样的原因:

SELECT '' As Empty
FROM dbo.TableA
ORDER BY Empty + ''

结果:

  

无效的列名称“空”。

因此,ORDER BY中的别名和表达式都允许使用别名,但不是。为什么,实施起来太难了?因为我主要是程序员,所以我认为别名是变量,可以简单地用在表达式中。

3 个答案:

答案 0 :(得分: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);

别名“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;
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 || '');
col_2
--
3
2
1

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

<强>的PostgreSQL

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

  

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

SELECT a + b AS sum, c FROM table1 ORDER BY sum + c;          -- wrong
  

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

SQL Server 2008中的文档错误

aliases in the ORDER BY clause相关的略微不同的问题。

  

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

除非我的咖啡因含量不足,否则这根本不是真的。此语句按SQL Server 2008和SQL Server 2012中的“test”。“col_1”进行排序。

select col_1 as col_2
from test
order by col_1;

答案 1 :(得分:0)

这个限制似乎与另一个限制有关,其中“列别名不能在同一个 SELECT 列表中被引用”。例如,这个查询:

SELECT Col1 AS ColAlias1 FROM T ORDER BY ColAlias1

可以翻译成:

SELECT Col1 AS ColAlias1 FROM T ORDER BY 1

这是一个合法的查询。但是这个查询:

SELECT Col1 AS ColAlias1 FROM T ORDER BY ColAlias1 + ' '

应该翻译成:

SELECT Col1 AS ColAlias1, ColAlias1 + ' ' FROM T ORDER BY 2

哪个会引发错误:

<块引用>

“字段列表”中的未知列“ColAlias1”

最后,这些似乎是因为 SQL 标准行为,而不是在实现中是不可能的。 更多信息请访问:Here

注意:最后一个查询可以由 MS Access 执行而不会出错,但会使用 SQL Server 引发上述错误。

答案 2 :(得分:-1)

您可以尝试以下方式:

select NewValue from (
  SELECT (CASE WHEN Value IS NULL THEN '<Null-Value>' ELSE Value END ) as NewValue, 
  ( CASE WHEN NewValue='<Null-Value>' THEN 1 ELSE 0 END) as ValOrder
  FROM dbo.TableA
  GROUP BY Value
) t
ORDER BY ValOrder