SQL Server2005 T-SQL 概览系列之一 逻辑查询处理

逻辑查询中的各个阶段
本节介绍逻辑查询所涉及的各个阶段。先描述每个阶段,然后再结合示例详细介绍。
逻辑查询处理的步骤序号
(8)   SELECT (9) DISTINCT (11) <TOP_specification> <select_list>
(1)   FROM <left_table>
(3)    <join_type> JOIN <right_table>
(2)     ON <join_condition>
(4)   WHERE <where_condition>
(5)   GROUP BY ALL <group_by_list>
(6)   WITH {CUBE | ROLLUP}
(7)   HAVING <having_condition>
(10) ORDER BY <order_by_list>

<join_type>:LEFT OUTER JOINRIGHT OUTER JOININNER JOINFULL OUTER JOIN
重要性:理解T-SQL查询的逻辑处理过程是写正确T-SQL的基础。上面是查询的一般形式,几乎包含我们在平时开发中所用到的所有T-SQL元素。(其中没有包括SQL Server 2005 新加入的元素:PIVOT、UNPIVOT、APPLY、OVER等)。
    SQL 不同于其他编程语言的最明显的特征是处理代码的顺序。在大多数编程语言中,代码是顺着处理的,但在SQL中,第一个被处理的子句是FROM子句。
    整个T—SQL的逻辑查询处理过程可以简单的理解成:查询过程中生成了一个虚拟的表(VT),在查询完成前VT对于调用者是不可见的。每个步骤所产生的VT都作为下一个步骤的输入,知道最后一步执行完成后,会把其中包含的数据返回给调用者。在整个过程中可分为两类操作:(1)向VT中填充数据,(2)从VT中删除不符合条件的数据。

逻辑查询处理阶段简介
1、 FROM:对FROM子句中的前两个表执行笛卡尔积(交叉联接),生成虚拟表VT1
2、ON:对VT1应用ON筛选器。只有那些使<join_condition>为真的行才被插入VT2
3、OUTER(JOIN):如果指定了OUTER JOIN 保留表中未找到匹配的行将作为外部行添加到VT2,生成VT3。如果FROM子句中包含两个以上的表,则对上一个联接生成的表和下一个表重复执行步骤1到步骤3,直到处理完所有的表为止。
4、WHERE:对VT3应用WHERE筛选器。只用使<where_condition>为TRUE的行才被插入VT4.
5、GROUP BY:按GROUP BY 子句中的列列表对VT4中的行分组,生成VT5.
6、CUBE|ROLLUP:把超组插入VT5,生成VT6.
7、Having:对VT6应用HAVING筛选器。只有使<having_condition>为TRUE的组才会被插入VT7.
8、SELECT:处理SELECT列表,产生VT8.
9、DISTINCT:将重复的行从VT8中移除,产生VT9.
10、ORDER BY:将VT9中的行按 ORDER BY 子句中的列列表排序,生成一个游标(VC10).
11、从VC10的开始处选择指定数量或比例的行,生成VT11,并返回给调用者。

Customers/Orders场景下的示例查询
代码清单1-2 表Customers和Orders的数据定义语言和示例数据

 1Set nocount on
 2use tempdb
 3go
 4if object_id('dbo.orders'is not null
 5 drop table dbo.orders
 6go
 7
 8if object_id('dbo.customers'is not null
 9 drop table dbo.customers
10go
11
12create table dbo.customers
13(
14 customerid char(5not null primary key,
15 city       nvarchar(10not null
16);
17insert into dbo.customers (customerid,city) values ('FISSA','Madrid');
18insert into dbo.customers (customerid,city) values ('FRNDO','Madrid');
19insert into dbo.customers (customerid,city) values ('KRLOS','Madrid');
20insert into dbo.customers (customerid,city) values ('MRPHS','Ziobn');
21
22create table dbo.orders
23(
24 orderid int not null primary key,
25 customerid char(5)  null references customers(customerid)
26);
27insert into dbo.orders (orderid,customerid) values (1,'FRNDO');
28insert into dbo.orders (orderid,customerid) values (2,'FRNDO');
29insert into dbo.orders (orderid,customerid) values (3,'KRLOS');
30insert into dbo.orders (orderid,customerid) values (4,'KRLOS');
31insert into dbo.orders (orderid,customerid) values (5,'KRLOS');
32insert into dbo.orders (orderid,customerid) values (6,'MRPHS');
33insert into dbo.orders (orderid,customerid) values (7,null);
34
35

代码清单1-3  查询:来自Madrid且订单数少于3的消费者

1select c.customerid, Count(o.orderid) as numbers
2from customers as c left outer join dbo.orders as o
3on c.customerid = o.customerid
4where c.city='Madrid'
5group by c.customerid 
6having count(o.orderid)<3
7order by numbers

查询结果
customerid    numbers
FISSA            0
FRNDO            2
逻辑查询步骤详解

步骤1 执行笛卡尔积(交叉联接) 

    对From子句的两个表执行笛卡尔积,生成虚拟表VT1。VT1左表的行和右表的行的每一个可能的组合都包含一行。如果左表包含n行,右表包含m行,VT1中将包含n×m行。该步骤中的VT1将包含28行(4×7)。
该步骤相当于执行如下语句:select c.*,o.* from customers as c, orders as o

步骤2:应用ON筛选器(联接条件)
ON筛选器是可以用于查询的三个筛选器(ON、WHERE和HAVING)中的一个。ON筛选器中的逻辑表达式被应用到上一步骤返回的虚拟表(VT1)中的所有行。只有使<链接条件>为TRUE的那些行才会包含在由步骤2返回的虚拟表(VT2)中。
注:这里涉及到了三值逻辑(TRUE、FALSE和UNKNOWN),稍后章节中会详细讲述。
步骤2返回的虚拟表(VT2)
 Match?    C.customerid      C.city      O.orderid    O.customerid
 TRUE       FRNDO             Madrid      1            FRNDO 
 TRUE       FRNDO             Madrid      2            FRNDO
 TRUE       KRLOS             Madrid      3            KRLOS
 TRUE       KRLOS             Madrid      4            KRLOS
 TRUE       KRLOS             Madrid      5            KRLOS
 TRUE       MRPHS             Zion        6            MRPHS

步骤3: 添加外部行
    这一步只与外部链接有关。通过指定一种外部联接(LEFT、RIGHT或FULL),可以把一个或两个输入表标记为保留表。把一个表标记为保留表表示你希望返回该表的所有行,即使<联接条件>过滤掉了一些行。左外部联接把左表标记为保留表,右外部联接把右表标记为保留表,完全外部联接把两个表都标记为保留表。步骤3返回VT2中的行以及保留表在步骤2被过滤掉的行。保留表中的行被称为外部行。外部行中非保留表中的属性被赋值为NULL。最后生成虚拟表VT3
    在这个示例中,保留表是customers:
    步骤3返回的虚拟表VT3
  C.customerid      C.city      O.orderid    O.customerid
  FRNDO             Madrid      1            FRNDO 
  FRNDO             Madrid      2            FRNDO
  KRLOS             Madrid      3            KRLOS
  KRLOS             Madrid      4            KRLOS
  KRLOS             Madrid      5            KRLOS
  MRPHS             Zion        6            MRPHS
  FISSA             Madrid      NULL         NULL

步骤4:应用WHERE筛选器
    对上一步返回的虚拟表中的所有行应用WHERE筛选器。只有符合<where_condition>的行才会成为该步骤所返回虚拟表的一部分。
注:关于逻辑筛选条件到底是用在ON中还是用在WHERE中在下一章节中详细描述。
    步骤4 返回的虚拟表 VT4
  C.customerid      C.city      O.orderid    O.customerid
  FRNDO             Madrid      1            FRNDO 
  FRNDO             Madrid      2            FRNDO
  KRLOS             Madrid      3            KRLOS
  KRLOS             Madrid      4            KRLOS
  KRLOS             Madrid      5            KRLOS
  FISSA             Madrid      NULL         NULL

步骤5:分组
上一步返回的行被分配到各个组。GROUP BY 子句中列列表的每一个唯一值组合成为一组。上一步返回的每个基行都被分配到一个组,且仅分配到一个组。得到虚拟表VT5。VT5由两部分组成:实际组构成的成组部分(group section)和由上一步返回的基行构成的原始部分(raw section)
步骤5得到的VT5
  Groups         Raw
  C.customerid   C.customerid      C.city      O.orderid    O.customerid
  FRNDO          FRNDO             Madrid      1            FRNDO 
                 FRNDO             Madrid      2            FRNDO
  KRLOS          KRLOS             Madrid      3            KRLOS
                 KRLOS             Madrid      4            KRLOS
                 KRLOS             Madrid      5            KRLOS
  FISSA          FISSA             Madrid      NULL         NULL

步骤6:应用CUBE或ROLLUP选项
    如果指定了CUBE或ROLLUP,将创建超组并把它添加到上一步返回的虚拟表中,生成虚拟表VT6

步骤7:应用HAVING筛选器
    对上一步返回的组应用HAVING筛选器。只有符合<having_condition>的组才会成为这一步骤返回的虚拟表(VT6)的一部分。
步骤7返回的虚拟表VT7
  C.customerid   C.customerid      C.city      O.orderid    O.customerid
  FRNDO          FRNDO             Madrid      1            FRNDO 
                 FRNDO             Madrid      2            FRNDO
  FISSA          FISSA             Madrid      NULL         NULL

步骤8:处理select列表
    尽管SELECT列表是查询中最先被指定的,但却被放到第8步处理。处理SELECT列表这一步用于构建最终要被返回给调用方的表。SELECT列表中的表达式可以是上一步返回的虚拟表的基列,也可以是对这些基列的操作。
步骤8返回的虚拟表VT8
  C.customerid              numorders
  FRNDO                     2
  FISSA                     0
步骤9:应用DISTINCT子句
    如果在查询中指定了DISTINCT子句,将从上一步返回的虚拟表中移除重复的行,并生成虚拟表VT9。

步骤10:应用ORDER BY 子句
    按照ORDER BY 子句中的列列表排序上一步骤返回的行,返回游标VC10.
步骤11:应用TOP选项
    TOP选项允许你指定要返回的行数或百分比。从游标(VC10)的最前面选择指定的行数,生成VT11并返回给调用者。
    下一章节详细介绍TOP和确定性

posted on 2008-07-03 15:40  蜗牛赛跑  阅读(593)  评论(0编辑  收藏  举报

导航