博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
T-SQL | 逻辑查询处理内幕学习
阅读量:3527 次
发布时间:2019-05-20

本文共 2209 字,大约阅读时间需要 7 分钟。

T-SQL是ANSI和ISO SQL标准的MS SQL扩展,其正式名称为Transact-SQL,但一般程序员都称其为T-SQL。本文是我学习《T-SQL查询》一书的读书笔记,为你讲解逻辑查询的内幕。

1逻辑查询处理的各个阶段

流程总览

阶段解释

(1)FROM:标识出查询的来源表,处理表运算符。每个运算符会应用一系列的子阶段。eg.在JOIN连接运算中涉及的阶段是笛卡尔积、ON筛选器和添加外部行。FROM阶段会生成一个虚拟表,这里暂定为VT1。

    • (1-J1)笛卡尔积:对涉及到的两个表执行笛卡尔积(交叉联接),生成虚拟表VT1-J1。

    • (1-J2)ON筛选器:对VT1-J1中的行根据ON子句中出现的谓词进行筛选。只有让该谓词取值为TRUE的行,才能插入到VT1-J2中。

    • (1-J3)添加外部行:如果指定了OUTER JOIN(相对于CROSS JOIN或INNER JOIN),则将保留表(Preserved Table)中没有找到匹配的行,作为外部行添加到VT1-J2中,生成VT1-J3。

(2)WHERE:根据在WHERE子句中出现的谓词对VT1中的行进行筛选。只有让谓词计算结果为TRUE的行,才会插入VT2中。

(3)GROUP BY:按照GROUP BY子句中指定的列名列表,将VT2中的行进行分组,生成VT3。最终,每个分组只有一个结果行。

(4)HAVING:根据HAVING子句出现的谓词对VT3中的分组进行筛选。只有让谓词计算结果为TRUE的行,才会插入VT4。

(5)SELECT:处理SELECT子句中的元素,产生VT5。

    • (5-1)计算表达式:计算SELECT列表中的表达式,生成VT5-1。

    • (5-2)DISTINCT:删除VT5-1中的重复行,生成VT5-2。

    • (5-3)TOP:根据ORDER BY子句定义的逻辑排序,从VT5-2中选择前面指定数量或百分比的行,生成VT5-3。

(6)ORDER BY:根据ORDER BY子句中指定的列名列表,对VT5-3中的行进行排序,生成游标VC6。

2一个逻辑查询的示例

示例场景

假设有两张表:Customers和Orders,表结构和数据如下:  

这里我们要查询来自Madrid并且订单数少于3个的客户,查询代码和结果也如下图所示:

阶段详解

(1)FROM阶段:

  •  
  •  
  •  
FROM dbo.Customers AS C  LEFT OUTER JOIN dbo.Orders AS O    ON C.customerid = O.customerid

步骤1-J1=>笛卡尔积

这里先不考虑LEFT OUTER,通过JOIN交叉联接后形成虚拟表VT1-J1:

步骤1-J2=>ON筛选器

ON筛选器的作用在于从上一步生成的虚拟表VT1-J1中的所有行中筛选出只有使 C.customerid = O.customerid 为TRUE的那些行,将其输出到新的虚拟表VT1-J2中。

步骤1-J3=>添加外部行

这一步只会在外链接(OUTER JOIN)中才会发生。这里是:Customers AS C LEFT OUTER JOIN Orders AS O,即Customer作为保留表。最终的虚拟表VT1-J3如下:

*.这里Customer作为保留表,所以FISSA虽然没有满足ON筛选器,但是也会被添加到虚拟表中。

(2)WHERE阶段

  •  
WHERE C.city = 'Madrid'

在此阶段会去掉VT1中客户为MRPHS的行(因为其cityid不是Madrid),生成如下所示的VT2:

ON和WHERE的区别:WHERE对行的删除是最终的,而ON对行的删除并不是,因此步骤1-J3添加外部行时会再添加回来。此外,只有当使用外连接时,ON和WHERE才存在这种逻辑区别。

(3)GROUP BY阶段:

  •  
GROUP BY C.customerid

这一步将VT2中的数据行按组进行重组,得到VT3如下图所示:

(4)HAVING阶段:

  •  
HAVING COUNT(O.orderid) < 3

这一步从VT3中进行筛选,只有使得COUNT(O.orderid)<3逻辑值为TRUE的组,才会进入到VT4。HAVING筛选器是唯一可用于分组数据的筛选器。

这里没有使用COUNT(*)是因为在外联接中,COUNT(*)会把外部行也统计在内,比如会将FISSA的订单数统计为1,这明显是错误的。

(5)SELECT阶段

步骤5-1=>计算表达式

  •  
SELECT C.customerid, COUNT(O.orderid) as numorders

得到VT5-1

步骤5-2=>应用DISTINCT子句

此示例木有DISTINCT子句,故VT5-1没有变化。

步骤5-3=>应用TOP选项

TOP选项时T-SQL特有的一项功能,允许指定要返回的行数或百分比。不过,此示例也没有指定TOP,估计VT5=VT5-1。

(6)ORDER BY阶段:

  •  
ORDER BY numorders

这一步将对VT5进行排序,返回游标VC6。ORDER BY子句也是唯一可以重用SELECT列表中创建的列别名的步骤。

Ref参考资料

[美] Itzik Ben-Gan 著,《SQL Server 2008技术内幕:T-SQL查询》

更多SQL文章: 

转载地址:http://mpwhj.baihongyu.com/

你可能感兴趣的文章
MyBatis-Plus代码生成器
查看>>
我的第一个SpringBoot项目(一)
查看>>
回文数
查看>>
伪背包问题!
查看>>
求10000以内n的阶乘!
查看>>
static关键字
查看>>
类的继承
查看>>
final关键字
查看>>
抽象类
查看>>
java的多态现象
查看>>
java中对象的类型转换
查看>>
java基础入门 String
查看>>
Java基础入门 StringBuffer类
查看>>
Java基础入门 currentTimeMillis方法
查看>>
Java基础入门 arraycopy方法
查看>>
Java基础入门 Math类
查看>>
Java基础入门 Random类
查看>>
Java基础入门 Date类
查看>>
Java基础入门 Calendar类
查看>>
Java基础入门 DateFormat类
查看>>