为什么 mySQL 能够在通常不能重用别名的情况下解析这些列别名?
Why is mySQL able to resolve these column aliases when normally one can't reuse an alias?
大多数 SQL 专家会说不能在同一级别的 select 中重复使用别名;通常使用 CTE 来解决这个问题;或者将查询包装为子查询,以便可以引用别名。但是,mySQL 似乎允许这种情况,前提是别名在 select 本身的 子查询 中被引用;所以技术上不是一个级别的。
SELECT CONCAT(a, b) AS c1, CONCAT((SELECT c1), 2)
FROM (SELECT 'a' a, 'b' b, 'c' c UNION ALL
SELECT '1', '2', '3') t1;
SELECT 1 a, 2 b, (SELECT A+B) c
, concat((SELECT a),(SELECT b)) d
, greatest((SELECT a),(SELECT b), (SELECT c))
以上两个查询都有效.. 是的;他们工作。 (或者做得很好,使它们看起来像工作)
虽然这不是:正如人们所期望的那样。
SELECT CONCAT(a, b) AS c1, CONCAT(c1, 2)
FROM (SELECT 'a' a, 'b' b, 'c' c UNION ALL
SELECT '1', '2', '3') t1;
所以这里的问题有两个:
这是 mySQL "feature" 缺少文档还是有人可以解释编译器如何解析别名?
这是一个可以依赖的文档化功能吗?如果是这样的话,这在哪里记录,以便人们可以理解使用这种方法的含义?
这个问题源于一个已经问过的问题:
这对我来说像是一个解析错误(在其他数据库中,您会在前两个查询中遇到错误)。
我能猜到发生了什么。 MySQL 正在解析子查询 (select c1)
。它在子查询中没有找到 c1
,所以它开始在外部查询中寻找引用。
根据SQL的规则,应该只查看from
子句中的列。但是,MySQL 似乎也在查看列别名。
尽管我将其称为错误,但 MySQL 似乎将其视为一项功能。 (又一个 MySQL 考虑 "bug" 和 "feature" 的例子。)考虑这个查询:
SELECT CONCAT((SELECT c1), 2), CONCAT(a, b) AS c1
FROM (SELECT 'a' a, 'b' b, 'c' c UNION ALL
SELECT '1', '2', '3') t1;
它产生的错误:
Reference 'c1' not supported (forward reference in item list)
错误表明 MySQL 正在有意解析 "backwards" 引用。
郑重声明,我绝不会依赖此功能。它不仅违反了 ANSI 标准,而且在数据库中具有独特的行为。这很混乱。考虑这个小修改:
SELECT CONCAT(a, b) AS c1, CONCAT((SELECT c1), 2)
FROM (SELECT 'a' a, 'b' b, 'c' c UNION ALL
SELECT '1', '2', '3') t1 CROSS JOIN
(SELECT 'abcdef' as c1) x;
查询解析到哪个 c1
?我会让你弄明白的。这甚至没有考虑到 c1
可能是一个变量。
- 调查使我 this statement:作为扩展 MySQL 也允许它们在 GROUP BY 和 HAVING 中。
但是,它们在 WHERE 子句和 SELECT 列表的其他部分 中无效。有关详细信息,请参阅 http://dev.mysql.com/doc/refman/5.7/en/problems-with-alias.html。然而,该部分没有具体讨论 select 和子查询中别名的重用。该错误似乎确实表明这是先前版本 (5.6.23) 中的一个功能,但在 5.7.9..
中没有
- 但是在上面 link 中还提供了以下信息:
[2015 年 12 月 9 日 15:35] Roy Lyseng
...
我读到了别名表达式(它们不能用在 WHERE 子句中),但问题出现了:
1.为什么它停止工作? 它停止工作是因为我们正在筛选 SQL 标准的 MySQL 扩展。并且在检查由于使用对别名表达式的引用的极端情况导致的一些崩溃错误时,决定此扩展定义不当并且可以通过其他方式处理。但是崩溃的错误是在 WHERE 子句中使用子查询,而不是在 SELECT 列表中。
2。为什么标准 SQL 被改变了? (或者它以前没有被提供给标准?) 这种结构从未成为标准 SQL 的一部分,它是对标准的 MySQL 扩展。除了在 ORDER BY 子句中外,该标准不允许引用别名。
3。是否存在查询将再次运行的配置选项,或者如何找到所有这些不起作用的请求?我们已经重新考虑了如何处理这个问题,并将尝试恢复不支持别名的决定在 SELECT 列表中的子查询中。因此,我们将重新打开该错误。
Here is a longer background for the original decision:
与 WHERE 子句中子查询中的别名引用相反(在 GROUP BY 中,就此而言),没有理由(标准合规性除外)我们不应该这样做允许引用 SELECT 列表 中的别名,因为它们应该在查询执行的同一阶段可用。但是 5.6 中的支持非常随意:
鉴于此:创建 table t1(a int, b int),
SELECT 列表中的别名无效:
select a+b as c,c+1 from t1;
ERROR 1054 (42S22): Unknown column 'c' in 'field list'
但在子查询中,对 c 的引用是有效的:
select a+b as c,(select c+1) from t1;
并且子查询必须在别名定义之后:
select (select c+1),a+b as c from t1;
ERROR 1247 (42S22): Reference 'c' not supported (forward reference in item list)
因此,很容易说 对 SELECT 列表 中别名的引用的支持是临时的.尽管如此,我们将尝试重新实现旧的解决方案,但不会尝试清理支持此功能的明显漏洞。但是在WHERE子句中的子查询中引用别名将不会被重新实现。
结论:
- 虽然在同一个 select 中引用别名与常识相反,但 mySQL 确实允许这样做。据我所知,这在任何其他 RDBMS 中都不常见。人们需要考虑识别别名的顺序(戈登的回答解决了人们需要考虑的 3 个地方)。
- 就我个人而言,除非可以找到解释其工作原理或将要工作的附加文档,否则我会倾向于放弃此功能。大多数开发人员会坚持使用 CTE 或子查询来处理别名重用,从维护的角度来看,这可能比标准方法更容易混淆。
- "Aliased Expressions" or "references to aliases in the SELECT list" 好像就是这个叫法。但我在这个 "feature" 的文档中找不到更多信息(意外后果?)
大多数 SQL 专家会说不能在同一级别的 select 中重复使用别名;通常使用 CTE 来解决这个问题;或者将查询包装为子查询,以便可以引用别名。但是,mySQL 似乎允许这种情况,前提是别名在 select 本身的 子查询 中被引用;所以技术上不是一个级别的。
SELECT CONCAT(a, b) AS c1, CONCAT((SELECT c1), 2)
FROM (SELECT 'a' a, 'b' b, 'c' c UNION ALL
SELECT '1', '2', '3') t1;
SELECT 1 a, 2 b, (SELECT A+B) c
, concat((SELECT a),(SELECT b)) d
, greatest((SELECT a),(SELECT b), (SELECT c))
以上两个查询都有效.. 是的;他们工作。 (或者做得很好,使它们看起来像工作)
虽然这不是:正如人们所期望的那样。
SELECT CONCAT(a, b) AS c1, CONCAT(c1, 2)
FROM (SELECT 'a' a, 'b' b, 'c' c UNION ALL
SELECT '1', '2', '3') t1;
所以这里的问题有两个:
这是 mySQL "feature" 缺少文档还是有人可以解释编译器如何解析别名?
这是一个可以依赖的文档化功能吗?如果是这样的话,这在哪里记录,以便人们可以理解使用这种方法的含义?
这个问题源于一个已经问过的问题:
这对我来说像是一个解析错误(在其他数据库中,您会在前两个查询中遇到错误)。
我能猜到发生了什么。 MySQL 正在解析子查询 (select c1)
。它在子查询中没有找到 c1
,所以它开始在外部查询中寻找引用。
根据SQL的规则,应该只查看from
子句中的列。但是,MySQL 似乎也在查看列别名。
尽管我将其称为错误,但 MySQL 似乎将其视为一项功能。 (又一个 MySQL 考虑 "bug" 和 "feature" 的例子。)考虑这个查询:
SELECT CONCAT((SELECT c1), 2), CONCAT(a, b) AS c1
FROM (SELECT 'a' a, 'b' b, 'c' c UNION ALL
SELECT '1', '2', '3') t1;
它产生的错误:
Reference 'c1' not supported (forward reference in item list)
错误表明 MySQL 正在有意解析 "backwards" 引用。
郑重声明,我绝不会依赖此功能。它不仅违反了 ANSI 标准,而且在数据库中具有独特的行为。这很混乱。考虑这个小修改:
SELECT CONCAT(a, b) AS c1, CONCAT((SELECT c1), 2)
FROM (SELECT 'a' a, 'b' b, 'c' c UNION ALL
SELECT '1', '2', '3') t1 CROSS JOIN
(SELECT 'abcdef' as c1) x;
查询解析到哪个 c1
?我会让你弄明白的。这甚至没有考虑到 c1
可能是一个变量。
- 调查使我 this statement:作为扩展 MySQL 也允许它们在 GROUP BY 和 HAVING 中。 但是,它们在 WHERE 子句和 SELECT 列表的其他部分 中无效。有关详细信息,请参阅 http://dev.mysql.com/doc/refman/5.7/en/problems-with-alias.html。然而,该部分没有具体讨论 select 和子查询中别名的重用。该错误似乎确实表明这是先前版本 (5.6.23) 中的一个功能,但在 5.7.9.. 中没有
- 但是在上面 link 中还提供了以下信息:
[2015 年 12 月 9 日 15:35] Roy Lyseng ...
我读到了别名表达式(它们不能用在 WHERE 子句中),但问题出现了:
1.为什么它停止工作? 它停止工作是因为我们正在筛选 SQL 标准的 MySQL 扩展。并且在检查由于使用对别名表达式的引用的极端情况导致的一些崩溃错误时,决定此扩展定义不当并且可以通过其他方式处理。但是崩溃的错误是在 WHERE 子句中使用子查询,而不是在 SELECT 列表中。
2。为什么标准 SQL 被改变了? (或者它以前没有被提供给标准?) 这种结构从未成为标准 SQL 的一部分,它是对标准的 MySQL 扩展。除了在 ORDER BY 子句中外,该标准不允许引用别名。
3。是否存在查询将再次运行的配置选项,或者如何找到所有这些不起作用的请求?我们已经重新考虑了如何处理这个问题,并将尝试恢复不支持别名的决定在 SELECT 列表中的子查询中。因此,我们将重新打开该错误。
Here is a longer background for the original decision:
与 WHERE 子句中子查询中的别名引用相反(在 GROUP BY 中,就此而言),没有理由(标准合规性除外)我们不应该这样做允许引用 SELECT 列表 中的别名,因为它们应该在查询执行的同一阶段可用。但是 5.6 中的支持非常随意:
鉴于此:创建 table t1(a int, b int),
SELECT 列表中的别名无效:
select a+b as c,c+1 from t1;
ERROR 1054 (42S22): Unknown column 'c' in 'field list'
但在子查询中,对 c 的引用是有效的:
select a+b as c,(select c+1) from t1;
并且子查询必须在别名定义之后:
select (select c+1),a+b as c from t1;
ERROR 1247 (42S22): Reference 'c' not supported (forward reference in item list)
因此,很容易说 对 SELECT 列表 中别名的引用的支持是临时的.尽管如此,我们将尝试重新实现旧的解决方案,但不会尝试清理支持此功能的明显漏洞。但是在WHERE子句中的子查询中引用别名将不会被重新实现。
结论:
- 虽然在同一个 select 中引用别名与常识相反,但 mySQL 确实允许这样做。据我所知,这在任何其他 RDBMS 中都不常见。人们需要考虑识别别名的顺序(戈登的回答解决了人们需要考虑的 3 个地方)。
- 就我个人而言,除非可以找到解释其工作原理或将要工作的附加文档,否则我会倾向于放弃此功能。大多数开发人员会坚持使用 CTE 或子查询来处理别名重用,从维护的角度来看,这可能比标准方法更容易混淆。
- "Aliased Expressions" or "references to aliases in the SELECT list" 好像就是这个叫法。但我在这个 "feature" 的文档中找不到更多信息(意外后果?)