一、关于T-SQL

  T-SQL是ANSI和ISO SQL标准的MS SQL扩展,其正式名称为Transact-SQL,但一般程序员都称其为T-SQL。

二、逻辑查询处理各个阶段

2.1 逻辑查询处理流程总览

2.2 逻辑查询处理阶段解释

  (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。

三、查询示例详解

3.1 示例场景

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

  

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

  

3.2 各阶段解释

  (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列表中创建的列别名的步骤

  

参考资料

  

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

作者:周旭龙

出处:http://edisonchou.cnblogs.com

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

《T-SQL查询》读书笔记Part 1.逻辑查询处理知多少的更多相关文章

  1. 《SQL Server 2012 T-SQL基础》读书笔记 - 2.单表查询

    Chapter 2 Single-Table Queries GROUP BY之后的阶段的操作对象就是组(可以把一组想象成很多行组成的)了,HAVING负责过滤掉一些组.分组后的COUNT(*)表示每 ...

  2. SQL.Cookbook 读书笔记2 查询结果排序

    第二章 查询结果排序 2.1 按查询字段排序 order by sal asc; desc;-- 3表示sal 2.2 按子串查询 );--按job的最后两个字符排序 2.3 对字符数字混合排序 cr ...

  3. 05 技术内幕 T-SQL 查询读书笔记(第四章)

    第四章 子查询:在外部查询内嵌套的内部查询(按照期望值的数量分为,标量子查询 scalar subqueries,多值子查询multivalued subqueries)(按照子查询对外部查询的依赖性 ...

  4. 《C#高效编程》读书笔记08-推荐使用查询语法而不是循环

    C#语言中并不缺少控制程序流程的结构,for.while.do/while和foreach等都可以做到这一点.但我们还有更好的方式:查询语法(query syntax) 下面这段代码演示了用命令式的方 ...

  5. SQL.Cookbook 读书笔记5 元数据查询

    第五章 元数据查询 查询数据库本身信息 表结构 索引等 5.1 查询test库下的所有表信息 MYSQL SELECT * from information_schema.`TABLES` WHERE ...

  6. SQL SERVER读书笔记:内存

    系统先操作地址空间,真正要用的时候才申请物理内存,进行使用. Reserved Memory  保留内存,虚拟内存 Commited Memory 提交内存,物理内存 [如何判断SQL SERVER ...

  7. SQL SERVER读书笔记:TempDB

    每次SQL SERVER启动的时候,会重新创建. 用于 0.临时表 1.排序 2.连接(merge join,hash join) 3.行版本控制 临时表与表变量的区别: 1)表变量是存储在内存中的, ...

  8. SQL SERVER读书笔记:执行计划

    执行计划对性能影响甚大. 系统是怎么得出一个号的执行计划的?主要是依赖于准确的统计信息.统计信息准确的前提下,执行语句重用性高,可避免频繁编译,这也有助于提高性能. 但如果怀疑统计信息不够准确,可以强 ...

  9. SQL.Cookbook 读书笔记3 操作多个表

    第三章 操作多个表 表连接的内连接和外连接 A表 B表id name id name 1 a 1 b 2 b 3 c4 c内连接就是左表和右表相同的数据,查询结果只有相等的数据:select * fr ...

随机推荐

  1. Linux Shell脚本攻略学习总结:三

    根据扩展名切分文件名 首先,我们先来看两个例子: file_jpg="sample.jgp" name=${file_jpg%.*} echo File name is : $na ...

  2. (十)弹出框Alert与ActionSheet

    第一种方式:中间弹窗 从中间弹出的窗口称为AlertView. 可以设置多个按钮,取消按钮会放在对右端或者最下端,按钮超过两个,会竖着排列. UIAlertView *alert = [[[UIAle ...

  3. 《java入门第一季》之面向对象(形式参数和返回值问题的深入研究3)

    /*     形式参数:         引用类型 接口:需要的是该接口的实现类对象 这个时候就没什么了,和抽象类的解释差不多. */ interface Love { public abstract ...

  4. Gradle 1.12用户指南翻译——第三十一章. FindBugs 插件

    其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Github上的地址: https://g ...

  5. 操作系统 - unix和windows下进程异同

    在UNIX系统中,只有一个系统调用可以用来创建新进程:fork.这个系统调用会创建一个与调用进程相同的副本.在调用了fork之后,这两个进程(父进程和子进程)拥有相同的存储映像.同样的环境字符串和同样 ...

  6. 集群RPC通信

    RPC即远程过程调用,它的提出旨在消除通信细节.屏蔽繁杂且易错的底层网络通信操作,像调用本地服务一般地调用远程服务,让业务开发者更多关注业务开发而不必考虑网络.硬件.系统的异构复杂环境. 先看看集群中 ...

  7. "《算法导论》之‘字符串’":字符串匹配

    本文主要叙述用于字符串匹配的KMP算法. 阮一峰的博文“字符串匹配的KMP算法"将该算法讲述得非常形象,可参考之. 字符串‘部分匹配值’计算 KMP算法重要的一步在于部分匹配值的计算.模仿& ...

  8. objective-c随机数+日期格式显示一例

    在原来的代码上有修改,主要为: 将准备随机数方法放到了init中,这样不用手动调用了 setWeek方法已经过时,使用的是setWeekOfYear方法 在此放一份以备以后查找: le.h // // ...

  9. C语言删除字符串中重复的字符

    #include <stdio.h> #include <string.h> #define NR(x) sizeof(x)/sizeof(x[0]) int Del_char ...

  10. Android Binder IPC详解-Android学习之旅(96)

    linux内存空间与BInder Driver Android进程和linux进程一样,他们只运行在进程固有的虚拟空间中.一个4GB的虚拟地址空间,其中3GB是用户空间,1GB是内核空间 ,用户空间是 ...