SELECT语句的目的是对表进行查询、应用一定的逻辑处理,并返回结果。注意,这里的“逻辑查询处理”是指ANSI SQL定义的概念模型,规定了如何处理一个查询,以及如何取得最终的结果。Microsoft SQL Server引擎并不教条地严格遵守逻辑查询处理;相反,在物理地处理一个查询时,它可以自由地调整处理阶段的顺序,只要最终的结果能够和逻辑查询处理的规定保持一致。SQL Server可以(事实上经常)在查询的物理处理中采用很多快捷方式。
我们使用以下代码来描述逻辑查询处理和各种SELECT查询字句:
USE TestDB SELECT empid,YEAR(orderdate) AS orderyear,COUNT(*) AS numorders FROM Sales.Orders WHERE custid=88 GROUP BY empid,YEAR(orderdate) HAVING COUNT(*) > 1 ORDER BY empid,orderyear;
这段代码开始先用一个USE语句来设置回话(session)的数据库上下文,此处是将其设置为TestDB数据库。如果会话已经位于需要查询的数据库上下文中,则不需要再使用USE语句。
我们首先看下SELECT语句中每个查询子句的逻辑处理顺序。在大多数编程语言中,代码行是按照它们的编写顺序来执行处理的。而在SQL语句中,情况则有些不同。即使SELECT子句在查询中最先出现,在逻辑上差不多是最后才处理它。各子句在逻辑上按以下顺序进行处理:
1、FROM
2、WHERE
3、GROUP BY
4、HAVING
5、SELECT
6、ORDER BY
所以即使我们上面的代码中在语法上以SELECT子句作为开始,而在逻辑上则应该按以下顺序来处理它的各个子句:
USE TestDB FROM Sales.Orders WHERE custid=88 GROUP BY empid,YEAR(orderdate) HAVING COUNT(*) > 1 SELECT empid,YEAR(orderdate) AS orderyear,COUNT(*) AS numorders ORDER BY empid,orderyear;
或者,以更便于阅读的方式来表述,我们的这条查询语句完成以下功能:
1、从Sales.Orders表中查询数据行。
2、对订单数据进行过滤,只保留客户ID等于88的记录。
3、按雇员ID和订单年份对订单进行分组。
4、对分组数据(雇员ID和订单年份)进行过滤,只保留具有多个订单的分组。
5、选择(返回)每个分组的雇员ID、订单年份,以及订单数量。
6、按照雇员ID和订单年份对输出结果进行排序。
可惜,我们不能按正常的逻辑顺序来编写查询语句,而必须先从SELECT语句写起。