首先让我给你介绍一个例子,然后我会问这个问题。 代码
SELECT
orderyear
,qty
FROM
Sales.OrderTotalsByYear;
给我一张看起来像这样的表格
orderyear qty
----------- -----------
2007 25489
2008 16247
2006 9581
我需要返回每年的订单年份、数量和历年的运行总量。也就是说,对于每一年,返回直到那一年的数量总和。因此,对于 View 中记录的最早年份(2006 年),运行总计等于当年的数量。对于第二年(2007 年),运行总计是第一年加上第二年的总和,依此类推。 代码看起来像这样
SELECT
orderyear
,qty
,(
SELECT
SUM(O2.qty)
FROM
Sales.OrderTotalsByYear AS O2
WHERE
O2.orderyear <= O1.orderyear
)
AS runqty
FROM
Sales.OrderTotalsByYear AS O1
ORDER BY
orderyear;
还有一张 table
orderyear qty runqty
----------- ----------- -----------
2006 9581 9581
2007 25489 35070
2008 16247 51317
现在,我了解这段代码的作用,但我不了解它的方式。我在过程和面向对象编程方面有经验,但这让我发疯。 如果查询以这样的方式进行
- FROM
- WHERE
- GROUP BY
- HAVING
- SELECT
- ORDER BY
那么它是如何利用内部和外部 SELECT 之间的关系将内部 SELECT 与外部 SELECT 结合起来的呢?外部 SELECT 是否先运行并在遇到表中的第一个元素时停止,然后内部 SELECT 开始运行 O2.orderyear <= O1.orderyear 为真的元素?还是发生了完全不同的事情?
最佳答案
逻辑上,对于系统生成的每一行(通过FROM
、WHERE
、GROUP BY
和HAVING
),系统将评估 SELECT
子句。作为每一行评估的一部分,系统将评估相关的子查询:
(
SELECT
SUM(O2.qty)
FROM
Sales.OrderTotalsByYear AS O2
WHERE
O2.orderyear <= O1.orderyear
)
使用当前行的 O1.orderyear
值。
但是,从实用的角度来看1,系统可能能够优化其对该子查询的评估。一个足够聪明的优化器,如果统计数据表明值得这样做,可能会决定按 orderyear
顺序评估外部查询,并创建一个已排序的 OrderTotalsByYear
表的副本按 orderyear
顺序(或使用已经表示此排序顺序的索引)。在这种情况下,系统将能够评估此子查询结果,而无需为外部查询的每一行重新扫描整个 OrderTotalsByYear
表。
优化器做什么只能通过获取执行计划来确定,并且取决于您的特定表 - 它们的结构、索引和其中包含的数据。
1SQL 是根据逻辑 处理顺序定义的。实现可以自由地以与逻辑处理顺序不同的顺序执行操作,前提是它们产生的结果与遵循逻辑处理顺序时所获得的结果相同2。通常,SQL 也被定义为处理集合,而不是指定逐行或从左到右处理。
2SQL Server 在这里采取了比它应有的更多的自由,并且可能会产生错误,而这些错误如果它遵循逻辑处理顺序就不会产生。呵呵。
关于sql - 无法理解运行聚合的工作原理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40524059/