摘要
没有逻辑上的理由无法做到这一点,但是这样做的好处很小,而且有些陷阱可能不会立即显现出来。
研究成果
我做了一些研究,发现了一些很好的信息。以下是格林尼治标准时间2012-08-09 17:49从可靠的主要来源(希望保持匿名)的直接报价:
首次发明SQL时,SELECT子句中没有别名。这是一个严重的缺陷,大约在1986年被ANSI标准化时已得到纠正。
该语言旨在成为“非过程性”语言,换句话说,是在不指定查找方式的情况下描述所需的数据。因此,据我所知,没有理由为什么SQL实现无法在处理整个查询之前解析整个查询,并允许在任何地方定义别名并在任何地方使用别名。例如,我看不到以下查询无效的任何原因:
select name, salary + bonus as pay
from employee
where pay > 100000
尽管我认为这是一个合理的查询,但是由于某些与实现相关的原因,某些基于SQL的系统可能会对别名的使用施加限制。听到SQL Server这样做我并不感到惊讶。
我对对SQL-86标准的进一步研究以及现代DBMS为什么不支持别名重用感兴趣,但是还没有时间进行深入研究感兴趣。对于初学者来说,我不知道从哪里获取文档或不知道究竟由谁组成委员会。有人可以帮忙吗?我还想了解更多有关SQL Server的原始Sybase产品的信息。
从这项研究和一些进一步的思考中,我开始怀疑在其他子句中使用别名虽然很可能,但与其他语言功能相比,对于DBMS制造商来说从来没有这么优先。由于不是很大的障碍,查询编写者很容易解决它,因此在其他方面投入精力并不是最佳选择。另外,它将是专有的,因为它显然不是SQL标准的一部分(尽管我正在等待确定更多信息),因此将是一个较小的改进,破坏了DBMS之间的SQL兼容性。相比之下,CROSS APPLY
(实际上只不过是允许外部引用的派生表)是一个巨大的变化,尽管专有提供了令人难以置信的表达能力,但其他方式却难以实现。
在各处使用别名的问题
如果允许将SELECT项放在WHERE子句中,则不仅会激增查询的复杂性(以及发现良好执行计划的复杂性),而且可能会提出完全不合逻辑的内容。尝试:
SELECT X + 5 Y FROM MyTable WHERE Y = X
如果MyTable已经具有Y列,WHERE子句引用的是该怎么办?解决方案是使用CTE或派生表,在大多数情况下,它们无需花费额外费用,但可以获得相同的最终结果。CTE和派生表至少通过允许仅使用一次别名来强制解决歧义。
同样,在FROM子句中不使用别名是很有意义的。您不能这样做:
SELECT
T3.ID + (SELECT Min(Interval) FROM Intervals WHERE IntName = 'T') CalcID
FROM
Table1 T
INNER JOIN Table2 T2
ON T2.ID = CalcID
INNER JOIN Table3 T3
ON T2.ID = T3.ID
这是一个循环引用(在这个意义上,T2被秘密地参照从T3的值,在此之前已经表中JOIN列表被呈现),并织补难以看清。这个怎么样:
INSERT dbo.FinalTransaction
SELECT
newid() FinalTransactionGUID,
'GUID is: ' + Convert(varchar(50), FinalTransactionGUID) TextGUID,
T.*
FROM
dbo.MyTable T
您想打赌newid()函数将被两次放入执行计划中,完全出乎意料地使两列显示不同的值是多少?如果在CTE或派生表中使用了N个级别的查询,该怎么办?我保证这个问题比您想象的要严重。有已经什么时候的事情仅计算一次,或者在查询计划什么时候严重不一致的问题,微软已经表示,它不会修复其中一些是因为它们正确表达了查询代数-如果获得意外结果,请将查询分解为多个部分。允许链接引用,通过可能很长的此类链来检测循环引用,这是非常棘手的问题。引入并行性,您将面临噩梦。
注意:在WHERE或GROUP BY中使用别名不会对newid()或rand()之类的函数产生影响。
创建可重用表达式的SQL Server方法
交叉应用/外部应用是SQL Server中创建可在查询中其他任何地方使用的表达式的一种方法(只是在FROM子句中不早):
SELECT
X.CalcID
FROM
Table1 T
INNER JOIN Table3 T3
ON T.ID = T3.ID
CROSS APPLY (
SELECT
T3.ID + (SELECT Min(Interval) FROM Intervals WHERE IntName = 'T') CalcID
) X
INNER JOIN Table2 T2
ON T2.ID = X.CalcID
这有两件事:
- 使CROSS APPLY中的所有表达式都获得一个“命名空间”(表别名,在此为X),并在该命名空间内唯一。
- 不仅使CalcID来自X,而且使在表T1和T3联接时为什么不能使用X的任何内容变得无处不在,这是显而易见的,因为尚未引入X。
我实际上很喜欢CROSS APPLY。它已经成为我忠实的朋友,并且我一直都在使用它。是否需要部分UNPIVOT(使用本机语法需要PIVOT / UNPIVOT或UNPIVOT / PIVOT)?完成与交叉申请。需要一个可以多次重用的计算值吗?做完了 是否需要严格执行链接服务器上的调用的执行顺序?完成-惊人的速度提高。仅需要将一种类型的行拆分为2行或有附加条件?做完了
因此至少,在DBMS SQL Server 2005及更高版本中,您没有其他抱怨的理由:CROSS APPLY是您以所需的方式进行干燥的方式。