在 GroupBy 中使用 SQL 别名

只是对 SQL 语法很好奇

SELECT
itemName as ItemName,
substring(itemName, 1,1) as FirstLetter,
Count(itemName)
FROM table1
GROUP BY itemName, FirstLetter

这是不正确的,因为

GROUP BY itemName, FirstLetter

真的应该

GROUP BY itemName, substring(itemName, 1,1)

但是为什么我们不能简单地用前者来方便呢?

224782 次浏览

至少在 PostgreSQL 中,可以在 GROUP BY 子句中使用结果集中的列号:

SELECT
itemName as ItemName,
substring(itemName, 1,1) as FirstLetter,
Count(itemName)
FROM table1
GROUP BY 1, 2

当然,如果您以交互方式执行此操作,并编辑查询以更改结果中列的数量或顺序,那么这开始是一个痛苦的过程。但还是。

有些 DBMS 允许您使用别名,而不必重复整个表达式。
Teradata 就是这样一个例子。

由于 这个所以问题中记录的原因,我避免使用比尔推荐的序位符号。

简单而健壮的替代方法是始终重复 GROUPBY 子句中的表达式。
DRY 不适用于 SQL。

您总是可以使用一个子查询,这样您就可以使用别名; 当然,检查性能(可能数据库服务器会同时运行两个查询,但是验证一下总没有坏处) :

SELECT ItemName, FirstLetter, COUNT(ItemName)
FROM (
SELECT ItemName, SUBSTRING(ItemName, 1, 1) AS FirstLetter
FROM table1
) ItemNames
GROUP BY ItemName, FirstLetter

回到以前,我发现 Rdb (Oracle 现在支持的以前的 DEC 产品)允许在 GROUPBY 中使用列别名。从版本11开始的主流 Oracle 不允许在 GROUPBY 中使用列别名。不确定 Postgreql、 SQLServer、 MySQL 等将允许还是不允许。YMMV.

由于处理的逻辑顺序,SQLServer 不允许引用 GROUPBY 子句中的别名。GROUPBY 子句在 SELECT 子句之前处理,因此在计算 GROUPBY 子句时不知道别名。这也解释了为什么可以在 ORDERBY 子句中使用别名。

这里有一个关于 SQLServer 逻辑处理阶段的信息来源。

SQL 的实现类似于按以下顺序执行查询:

  1. FROM 子句
  2. WHERE 子句
  3. GROUP BY 子句
  4. HAVING 条款
  5. SELECT 子句
  6. ORDERBY 子句

对于大多数关系数据库系统,这个顺序解释了哪些名称(列或别名)是有效的,因为它们必须在前一步中引入。

因此,在 Oracle 和 SQLServer 中,不能在在 SELECT 子句中定义的 GROUPBY 子句中使用术语,因为 GROUPBY 在 SELECT 子句之前执行。

但也有例外: MySQL 和 Postgres 似乎有额外的智能性,允许它们这样做。

在 SQLite 中对视图的结果进行分组时,要注意使用别名。如果别名与任何基础表(视图)的列名相同,则会得到意外的结果

注意,在 GroupBy (对于支持它的服务,如 postgres)中使用别名可能会产生意外的结果。例如,如果创建的别名已经存在于内部语句中,GroupBy 将选择内部字段名称。

-- Working example in postgres
select col1 as col1_1, avg(col3) as col2_1
from
(select gender as col1, maritalstatus as col2,
yearlyincome as col3 from customer) as layer_1
group by col1_1;


-- Failing example in postgres
select col2 as col1, avg(col3)
from
(select gender as col1, maritalstatus as col2,
yearlyincome as col3 from customer) as layer_1
group by col1;

我不会回答为什么会这样,但是我只是想通过使用 CROSS APPLY创建别名来说明一种在 SQLServer 中绕过这个限制的方法。然后在 GROUP BY子句中使用它,如下所示:

SELECT
itemName as ItemName,
FirstLetter,
Count(itemName)
FROM table1
CROSS APPLY (SELECT substring(itemName, 1,1) as FirstLetter) Alias
GROUP BY itemName, FirstLetter

至少在 Postgres 中,您可以在 group by 子句中使用别名:

选择 ItemName 作为 ItemName1, Substring (itemName,1,1)作为第一个字母, Count (itemName) 来自表1 按项目名称1,第一个字母分组;

我不建议将别名重命名为大写改变,因为这会造成混淆。