SQL – 在Group By中使用别名
只是好奇的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)
但是为什么我们不能简单地使用前者呢?
SQL按照如下顺序执行查询:
- FROM子句
- WHERE子句
- GROUP BY子句
- HAVING子句
- SELECT子句
- ORDER BY子句
对于大多数关系数据库系统来说,这个顺序解释了哪些名称(列或别名)是有效的,因为它们必须在前面的步骤中引入。
因此,在Oracle和SQL Server中,不能在SELECT子句中定义的GROUP BY子句中使用一个术语,因为GROUP BY是在SELECT子句之前执行的。
但是有一些例外情况:MySQL和Postgres似乎有更多的智能。
你总是可以使用子查询,所以你可以使用别名; 当然,检查性能(可能的数据库服务器将运行两个相同的,但从来没有伤害validation):
SELECT ItemName, FirstLetter, COUNT(ItemName) FROM ( SELECT ItemName, SUBSTRING(ItemName, 1, 1) AS FirstLetter FROM table1 ) ItemNames GROUP BY ItemName, FirstLetter
至less在PostgreSQL中,您可以在GROUP BY子句的结果集中使用列号:
SELECT itemName as ItemName, substring(itemName, 1,1) as FirstLetter, Count(itemName) FROM table1 GROUP BY 1, 2
当然,如果你正在交互地进行这个操作,那么开始会很痛苦,并且编辑这个查询来改变结果中列的数量或顺序。 但仍然。
由于处理的逻辑顺序,SQL Server不允许您引用GROUP BY子句中的别名。 GROUP BY子句在SELECT子句之前处理,所以在评估GROUP BY子句时不知道别名。 这也解释了为什么你可以在ORDER BY子句中使用别名。
以下是有关SQL Server逻辑处理阶段的信息的来源。
注意,在Group By中使用别名(对于支持它的服务,如postgres)可能会有意外的结果。 例如,如果您创build内部语句中已存在的别名,则分组依据将select内部字段名称。
-- 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;
一些DBMS会让你使用别名,而不必重复整个expression式。
Teradata就是这样一个例子。
根据这个SO问题中logging的原因,我避免了Bill所build议的序号表示法。
简单而强大的替代方法是始终在GROUP BY子句中重复expression式。
DRY不适用于SQL。
在SQLite中将视图结果分组时,请小心使用别名。 如果别名与任何基础表(对视图)的列名相同,您将得到意外的结果。
早在那一天,我发现现在由Oracle支持的前DEC产品Rdb允许在GROUP BY中使用列别名。 通过版本11的主streamOracle不允许在GROUP BY中使用列别名。 不知道Postgresql,SQL Server,MySQL等将会或不会允许。 因人而异。
我不回答为什么是这样,但只是想通过使用CROSS APPLY
创build别名来显示在SQL Server中的这种限制的方法。 然后在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