在 ORDER BY 中使用带有别名列的计算
Using calculation with an an aliased column in ORDER BY
众所周知,ORDER BY
子句是在SELECT
子句之后处理的,所以在SELECT
子句中可以使用列别名。
但是,我发现我不能在 ORDER BY
子句的计算中使用别名列。
WITH data AS(
SELECT *
FROM (VALUES
('apple'),
('banana'),
('cherry'),
('date')
) AS x(item)
)
SELECT item AS s
FROM data
-- ORDER BY s; -- OK
-- ORDER BY item + ''; -- OK
ORDER BY s + ''; -- Fails
我知道有其他方法可以执行此特定查询,而且我知道这是一个微不足道的计算,但我想知道为什么列别名在计算中不起作用。
我已经在 PostgreSQL、MariaDB、SQLite 和 Oracle 中进行了测试,它按预期工作。 SQL服务器似乎是奇数。
这仅仅是因为表达式的计算方式。一个更说明性的例子:
;WITH data AS
(
SELECT * FROM (VALUES('apple'),('banana')) AS sq(item)
)
SELECT item AS s
FROM data
ORDER BY CASE WHEN 1 = 1 THEN s END;
这 returns 相同的 Invalid column name
错误。在解析 select 列表中的别名之前计算 CASE
表达式(以及更简单情况下的 s + ''
的串联)。
一种更简单的解决方法是在 select 列表中附加空字符串:
SELECT
item + '' AS s
...
ORDER BY s;
还有更复杂的方法,比如使用派生的 table 或 CTE:
;WITH data AS
(
SELECT * FROM (VALUES('apple'),('banana') AS sq(item)
),
step2 AS
(
SELECT item AS s FROM data
)
SELECT s FROM step2 ORDER BY s+'';
这就是 SQL 服务器的工作方式,我想你可以说“好吧 SQL 服务器因此很糟糕”,但 SQL 服务器也可以说“这个用例到底是什么?” :-)
documentation 明确指出:
The column names referenced in the ORDER BY clause must correspond to
either a column or column alias in the select list or to a column
defined in a table specified in the FROM clause without any
ambiguities. If the ORDER BY clause references a column alias from
the select list, the column alias must be used standalone, and not as
a part of some expression in ORDER BY clause:
从技术上讲,您的查询应该有效,因为 order by 子句在 逻辑上 在 select 子句之后计算,并且它应该可以访问 [=25= 中声明的所有表达式] 条款。但是如果 查看 可以访问 SQL 规范,我无法评论它是否是 SQL 服务器或其他 RDBMS 的限制,将其作为奖励功能实现。
无论如何,您可以使用 CROSS APPLY
作为技巧....它是 FROM
子句的一部分,因此表达式应该在所有后续子句中可用:
SELECT item
FROM t
CROSS APPLY (SELECT item + '') AS CA(item_for_sort)
ORDER BY item_for_sort
众所周知,ORDER BY
子句是在SELECT
子句之后处理的,所以在SELECT
子句中可以使用列别名。
但是,我发现我不能在 ORDER BY
子句的计算中使用别名列。
WITH data AS(
SELECT *
FROM (VALUES
('apple'),
('banana'),
('cherry'),
('date')
) AS x(item)
)
SELECT item AS s
FROM data
-- ORDER BY s; -- OK
-- ORDER BY item + ''; -- OK
ORDER BY s + ''; -- Fails
我知道有其他方法可以执行此特定查询,而且我知道这是一个微不足道的计算,但我想知道为什么列别名在计算中不起作用。
我已经在 PostgreSQL、MariaDB、SQLite 和 Oracle 中进行了测试,它按预期工作。 SQL服务器似乎是奇数。
这仅仅是因为表达式的计算方式。一个更说明性的例子:
;WITH data AS
(
SELECT * FROM (VALUES('apple'),('banana')) AS sq(item)
)
SELECT item AS s
FROM data
ORDER BY CASE WHEN 1 = 1 THEN s END;
这 returns 相同的 Invalid column name
错误。在解析 select 列表中的别名之前计算 CASE
表达式(以及更简单情况下的 s + ''
的串联)。
一种更简单的解决方法是在 select 列表中附加空字符串:
SELECT
item + '' AS s
...
ORDER BY s;
还有更复杂的方法,比如使用派生的 table 或 CTE:
;WITH data AS
(
SELECT * FROM (VALUES('apple'),('banana') AS sq(item)
),
step2 AS
(
SELECT item AS s FROM data
)
SELECT s FROM step2 ORDER BY s+'';
这就是 SQL 服务器的工作方式,我想你可以说“好吧 SQL 服务器因此很糟糕”,但 SQL 服务器也可以说“这个用例到底是什么?” :-)
documentation 明确指出:
The column names referenced in the ORDER BY clause must correspond to either a column or column alias in the select list or to a column defined in a table specified in the FROM clause without any ambiguities. If the ORDER BY clause references a column alias from the select list, the column alias must be used standalone, and not as a part of some expression in ORDER BY clause:
从技术上讲,您的查询应该有效,因为 order by 子句在 逻辑上 在 select 子句之后计算,并且它应该可以访问 [=25= 中声明的所有表达式] 条款。但是如果 查看 可以访问 SQL 规范,我无法评论它是否是 SQL 服务器或其他 RDBMS 的限制,将其作为奖励功能实现。
无论如何,您可以使用 CROSS APPLY
作为技巧....它是 FROM
子句的一部分,因此表达式应该在所有后续子句中可用:
SELECT item
FROM t
CROSS APPLY (SELECT item + '') AS CA(item_for_sort)
ORDER BY item_for_sort