2010-10-01 37 views
88

只是对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) 

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

+5

这是允许的在PostgreSQL – 2010-10-01 18:11:50

+3

MySQL允许它也 – Kip 2013-08-09 19:40:16

+0

SQLite的允许它 – 2015-02-26 12:45:33

回答

161

SQL实现:

  1. FROM子句
  2. WHERE子句
  3. GROUP BY子句
  4. HAVING子句
  5. SELECT子句
  6. ORDER BY子句

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

因此,在Oracle和SQL Server中,不能在SELECT子句中定义的GROUP BY子句中使用一个术语,因为GROUP BY是在SELECT子句之前执行的。

虽然有例外:MySQL和Postgres似乎有更多的智能,允许它。

+0

我喜欢这个解释。尽管我无法推测将它作为语法糖添加到引擎是多么困难。 – Haoest 2010-10-01 20:23:31

+8

任何想法,如果数据库足够聪明,实现相同的表达式是在SELECT和GROUP BY子句中,而不重新评估表达式?即如果有'GROUP BY substring(itemName,1,1)',数据库足够聪明,不会在SELECT子句中获得重新计算子字符串的性能命中率? – Kip 2013-08-09 19:42:06

+8

在具有分组的查询的SELECT子句中,您只能访问GROUP BY表达式和聚合值。所以这不是关于聪明;它必须以这种方式来实现分组的工作。 (这是SQL标准所要求的)。但即使在更微不足道的情况下(例如WHERE和SELECT子句中的表达式相同),最先进的数据库系统也只会计算一次。这种优化称为*常见的子表达式消除*。 – Codo 2013-08-09 19:50:18

11

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

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

当然,这开始是一个痛苦,如果你是交互这样做的,您编辑查询更改结果中列的数量或顺序。但仍然。

+0

'GROUP BY FirstLetter'被允许在PostgreSQL。也就是说,试试在Postgresql中运行这个:select substring(table_name,1,2)作为tname from information_schema.tables group by tname – 2010-10-01 18:09:30

+1

@MichaelBuen似乎对我有潜在的问题。从一个快速测试看起来,如果有一个别名和一个同名的基表列,后者会优先吗? [SQL Fiddle](http://sqlfiddle.com/#!15/d41d8/1920)。因此,如果依靠别名后面的模式更改可能会默默地破坏您的查询并更改语义。 – 2014-05-01 16:07:18

+0

@MartinSmith现在只知道这是一个陷阱,不会使用它,谢谢。鉴于PostgreSQL允许该快捷方式,他们应该给予别名优先级,否则他们不应该允许该快捷方式。 – 2014-05-02 06:53:35

2

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

由于Bill在this SO question中记录的原因,我避免使用序号位置表示法。

简单且强大的替代方法是始终在GROUP BY子句中重复表达式。
DRY不适用于SQL。

22

您可以随时使用子查询,以便您可以使用别名;当然,检查性能(可能在数据库服务器将运行两个相同,但绝不会伤害到验证):

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

谢谢,好主意! – digz6666 2017-03-23 05:15:21

0

回到我发现,RDB,现在Oracle支持前DEC产品允许的一天要在GROUP BY中使用的列别名。通过版本11的主流Oracle不允许在GROUP BY中使用列别名。不知道Postgresql,SQL Server,MySQL等将会或不会允许。因人而异。

8

由于逻辑处理顺序,SQL Server不允许您引用GROUP BY子句中的别名。 GROUP BY子句在SELECT子句之前处理,所以在评估GROUP BY子句时不知道别名。这也解释了为什么你可以在ORDER BY子句中使用别名。

这是有关SQL Server logical processing phases的信息的源代码。仿佛查询是按以下顺序执行

1

当在SQLite中对视图中的结果进行分组时,请小心使用别名。如果别名与任何基础表的列名(视图)相同,您将得到意外的结果。

3

请注意,在Group By中使用别名(对于支持它的服务,如postgres)可以有意想不到的结果。例如,如果您创建内部语句中已经存在的别名,则分组依据将选择内部字段名称。

-- 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; 
0

我不回答为什么它是如此,但只是想用CROSS APPLY创建别名显示围绕在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