SQL - 在 Group By 中使用别名
Posted
技术标签:
【中文标题】SQL - 在 Group By 中使用别名【英文标题】:SQL - using alias in Group By 【发布时间】:2011-04-19 23:16:52 【问题描述】:只是对 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)
但是为什么我们不能为了方便而简单地使用前者呢?
【问题讨论】:
Postgresql 中允许的 mysql 也允许 你说的是哪个rdbms? 这个问题不是group by
独有的,也可以是join
的,比如
【参考方案1】:
至少在 PostgreSQL 中,您可以在 GROUP BY 子句中使用结果集中的列号:
SELECT
itemName as ItemName,
substring(itemName, 1,1) as FirstLetter,
Count(itemName)
FROM table1
GROUP BY 1, 2
当然,如果您以交互方式执行此操作并编辑查询以更改结果中列的数量或顺序,这将开始很痛苦。但还是。
【讨论】:
GROUP BY FirstLetter
在 Postgresql 中是允许的。也就是说,尝试在 Postgresql 中运行它: select substring(table_name,1,2) as tname from information_schema.tables group by tname
@MichaelBuen 对我来说似乎有问题。从快速测试来看,好像有一个别名和一个同名的基表列,后者优先? SQL Fiddle。因此,如果通过别名依赖此组,则以后的架构更改可能会默默地破坏您的查询并更改语义。
@MartinSmith 现在才知道这是一个陷阱,将避免使用它,谢谢。鉴于 PostgreSQL 允许该快捷方式,他们应该优先考虑别名,否则他们根本不应该允许该快捷方式。
这是 PostgreSQL 设计者的一个糟糕的想法。当您尝试 GROUP BY
任何包含聚合函数或窗口函数的表达式时,就会感到困惑,这“显然”不起作用。【参考方案2】:
某些 DBMS 允许您使用别名,而不必重复整个表达式。 Teradata 就是这样一个例子。
出于this SO question 中记录的原因,我避免使用 Bill 推荐的序数位置符号。
简单而可靠的替代方法是始终在 GROUP BY 子句中重复该表达式。 DRY 不适用于 SQL。
【讨论】:
【参考方案3】:您始终可以使用子查询,以便使用别名;当然,检查性能(数据库服务器可能会运行相同,但永远不会有坏处验证):
SELECT ItemName, FirstLetter, COUNT(ItemName)
FROM (
SELECT ItemName, SUBSTRING(ItemName, 1, 1) AS FirstLetter
FROM table1
) ItemNames
GROUP BY ItemName, FirstLetter
【讨论】:
由于性能不佳,应尽可能避免子查询。使用函数的副本要好得多,因为它当然会被数据库优化器检测到并且只执行一次。 @Roland 但在这种情况下执行计划没有什么不同。还有其他性能考虑吗? @Roland,应该避免相关子查询或其他导致循环或逐行行为的语法,并且嵌套子查询的深度是有限制的,但它是通常不正确子查询会导致性能不佳。在这种情况下,正如 Chris 所说,您可以验证执行计划(AKA 查询计划,解释计划)比较有和没有子查询,看看是否真的有任何区别。几乎每个数据库引擎都会重写您的查询,因此您无法完全控制执行的内容。这就是声明式语法的重点。【参考方案4】:以前我发现 Rdb(现在由 Oracle 支持的前 DEC 产品)允许在 GROUP BY 中使用列别名。 11 版之前的主流 Oracle 不允许在 GROUP BY 中使用列别名。不确定 Postgresql、SQL Server、MySQL 等会或不会允许。 YMMV。
【讨论】:
【参考方案5】:由于处理的逻辑顺序,SQL Server 不允许您在 GROUP BY 子句中引用别名。 GROUP BY 子句在 SELECT 子句之前处理,因此在评估 GROUP BY 子句时不知道别名。这也解释了为什么可以在 ORDER BY 子句中使用别名。
这是SQL Server logical processing phases 的信息来源之一。
【讨论】:
【参考方案6】:SQL 的实现就像按以下顺序执行查询一样:
-
FROM 子句
WHERE 子句
GROUP BY 子句
HAVING 子句
SELECT 子句
ORDER BY 子句
对于大多数关系数据库系统,此顺序解释了哪些名称(列或别名)是有效的,因为它们必须在上一步中引入。
因此,在 Oracle 和 SQL Server 中,您不能在 GROUP BY 子句中使用您在 SELECT 子句中定义的术语,因为 GROUP BY 在 SELECT 子句之前执行。
但也有例外:MySQL 和 Postgres 似乎有额外的智能允许它。
【讨论】:
我喜欢这个解释。虽然我无法推测将它作为语法糖添加到引擎中是多么困难。 知道数据库是否足够聪明,可以在不重新评估表达式的情况下在 SELECT 和 GROUP BY 子句中实现相同的表达式?即如果有GROUP BY substring(itemName, 1,1)
,数据库是否足够聪明,不会因为在 SELECT 子句中重新计算子字符串而对性能造成影响?
在带有分组的查询的 SELECT 子句中,您只能访问 GROUP BY 表达式和聚合值。所以这与聪明无关;必须以这种方式实现分组才能工作。 (并且它是 SQL 标准所要求的)。但即使在更琐碎的情况下(例如 WHERE 和 SELECT 子句中的相同表达式),最先进的数据库系统肯定只会计算一次。这种优化称为通用子表达式消除。
执行顺序与问题有什么关系?这不像提问者试图在 COUNT() 上进行 GROUP BY。事实上,所要求的查询在 MySQL 和可能的 PostgreSQL 中工作得很好,正如 cmets 中所指出的那样。
对于 mysql,sql_mode
不包括位掩码中的 ONLY_FULL_GROUP_BY,优化器有机会提供 better results,并在HAVING
子句。【参考方案7】:
在 SQLite 中对视图的结果进行分组时,请注意使用别名。如果别名与任何基础表的列名相同(对于视图),您将得到意想不到的结果。
【讨论】:
【参考方案8】:注意在 Group By 中使用别名(对于支持它的服务,例如 postgres)可能会产生意想不到的结果。例如,如果您创建的别名已存在于内部语句中,则 Group By 将选择内部字段名称。
-- 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;
【讨论】:
【参考方案9】:我没有回答为什么会这样,而只是想通过使用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
【讨论】:
【参考方案10】:至少在 Postgres 中,可以在 group by 子句中使用别名:
选择 itemName 作为 ItemName1, substring(itemName, 1,1) 作为 FirstLetter, 计数(项目名称) 从表 1 GROUP BY ItemName1, FirstLetter;
我不建议将别名重命名为大小写更改,这会导致混淆。
【讨论】:
以上是关于SQL - 在 Group By 中使用别名的主要内容,如果未能解决你的问题,请参考以下文章