T-SQL查询的逻辑工作原理
2008-11-10 09:51
316 查看
很多朋友都会使用T-SQL编写查询,但实际上对于其工作原理大多知之甚少。下面我们来分析一下查询的逻辑工作原理,也就是说一个查询到底是怎么一步一步的工作,最终给我们展示数据的。
认真观察下面这个图。想想看,这是我们常写的语句,你真的有没有想过哪个部分是先执行,而哪是个后面执行的呢
ON,WHERE,HAVING是三种筛选的子句。正因为他们是在SELECT语句执行之前执行的,所以他们所用的表达式是不可以为SELECT子句中重命名的列的
他们还有一个共同特征,如果比较运算符的一个部分为NULL,则既不返回TRUE也不返回FALSE,而是返回UNKNOWN
下面我们用一个实例来讲解这些步骤
第一步:准备实验环境和数据
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
认真观察下面这个图。想想看,这是我们常写的语句,你真的有没有想过哪个部分是先执行,而哪是个后面执行的呢
ON,WHERE,HAVING是三种筛选的子句。正因为他们是在SELECT语句执行之前执行的,所以他们所用的表达式是不可以为SELECT子句中重命名的列的
他们还有一个共同特征,如果比较运算符的一个部分为NULL,则既不返回TRUE也不返回FALSE,而是返回UNKNOWN
下面我们用一个实例来讲解这些步骤
第一步:准备实验环境和数据
SETNOCOUNTON; USEtempdb; GO IFOBJECT_ID('dbo.Orders')ISNOTNULL DROPTABLEdbo.Orders; GO IFOBJECT_ID('dbo.Customers')ISNOTNULL DROPTABLEdbo.Customers; GO CREATETABLEdbo.Customers ( customeridCHAR(5)NOTNULLPRIMARYKEY, cityVARCHAR(10)NOTNULL ); INSERTINTOdbo.Customers(customerid,city)VALUES('FISSA','Madrid'); INSERTINTOdbo.Customers(customerid,city)VALUES('FRNDO','Madrid'); INSERTINTOdbo.Customers(customerid,city)VALUES('KRLOS','Madrid'); INSERTINTOdbo.Customers(customerid,city)VALUES('MRPHS','Zion'); CREATETABLEdbo.Orders ( orderidINTNOTNULLPRIMARYKEY, customeridCHAR(5)NULLREFERENCESCustomers(customerid) ); INSERTINTOdbo.Orders(orderid,customerid)VALUES(1,'FRNDO'); INSERTINTOdbo.Orders(orderid,customerid)VALUES(2,'FRNDO'); INSERTINTOdbo.Orders(orderid,customerid)VALUES(3,'KRLOS'); INSERTINTOdbo.Orders(orderid,customerid)VALUES(4,'KRLOS'); INSERTINTOdbo.Orders(orderid,customerid)VALUES(5,'KRLOS'); INSERTINTOdbo.Orders(orderid,customerid)VALUES(6,'MRPHS'); INSERTINTOdbo.Orders(orderid,customerid)VALUES(7,NULL);
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
以上语句是在tempdb中创建了两个表,分别表示客户信息和订单信息。订单表与客户表是通过customerid进行连接的。我们也分别为他们输入了一些数据。如下面所示
第二步:准备一个查询做测试
/* 一个测试查询,检索那些订单个数小于3的客户,并且按订单总数排序(升序) */ SELECTC.customerid,COUNT(O.orderid)ASnumorders FROMdbo.CustomersASC LEFTOUTERJOINdbo.OrdersASO ONC.customerid=O.customerid WHEREC.city='Madrid' GROUPBYC.customerid HAVINGCOUNT(O.orderid)<3 ORDERBYnumorders;
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
同样是很简单的一个查询,它返回是订单总数小于3的客户。如下所示
很多朋友研究到这里就停止了,不过,我们下面要详细的分析这个查询的结果是怎么出来的
/*第一步:处理FROM子句,把来源的表进行CROSSJOIN(笛卡尔乘积) 我这里把结果做一个生成表查询,写到一个临时表(VT1)中去 */ SELECTC.customeridasCustomer,c.city,o.*INTO#VT1FROMdbo.CustomersC,dbo.OrdersO SELECT*FROM#VT1 --返回28行数据(4*7)
--第二步:处理ON子句,只把那些两个表的customerid匹配的行找出来,我把它们放到VT2中去
SELECTtemp.*INTO#VT2FROM(SELECT*FROM#VT1WHERECustomer=customerid)temp
SELECT*FROM#VT2
--返回6行数据
--第三步:根据JOIN语句的类型,决定是否要添加行到VT2中去,例如如果是LEFTJOIN的话,那么就要检查坐边的表(我们这里是customers表)的连接键值是否都存在,如果不存在就要去添加到VT2中
SELECTtemp.*INTO#VT3FROM
(SELECT*FROM#VT2
UNIONALL
SELECTCustomerID,City,NULL,NULLFROMdbo.CustomerscWHERENOTEXISTS(SELECTDISTINCTCustomerFROM#VT2WHERECustomer=c.CustomerID))temp
SELECT*FROM#VT3
--返回7行数据,其中有一个客户,因为没有订单,这一步中被添加进来。它的Orders的记录被标记为NULL
--第四步:处理WHERE子句,对VT3的结果集进行过滤,我们的条件是city=Madid
SELECTtemp.*INTO#VT4FROM
(SELECT*FROM#VT3WHEREcity='Madrid')temp
SELECT*FROM#VT4
--返回6行数据,因为有一个客户不是这个城市的
--第五步:处理GROUP子句,进行分类汇总
SELECTtemp.*INTO#VT5FROM
(SELECTCustomer,COUNT(OrderID)asorderidcount,COUNT(city)ascitycount,Count(customerid)ascustomeridcountFROM#VT4GROUPBYCustomer)temp
SELECT*FROM#VT5
--返回3行数据,根据客户分组,统计了订单的个数
--这里会不会去统计其他列的汇总呢
更正:这一步,逻辑上的数据结构是下面这样的,也就是说其实并没有计算。而是分组
--因为没有WITHRollup和WITHCube语句,所以跳过第六步,进入HAVING子句的处理
--第六步:处理HAVING子句,对GROUP之后的结果进行筛选,我们这里的条件是orderidcount<3
SELECTtemp.*INTO#VT6FROM
(SELECT*FROM#VT5WHEREorderidcount<3)temp
SELECT*FROM#VT6
--返回2行数据
--第七步:使用SELECT的字段列表过滤结果集
SELECT#VT6.Customer,#VT6.orderidcountasnumordersINTO#VT7FROM#VT6
SELECT*FROM#VT7
--还是2行数据,只不过只有两个列了
SELECT返回的结果在内部其实是一个游标集,本身并没有顺序,它就好比是一个集合。
--第八步:跳过DISTINCT,进行OrderBy操作
SELECT#VT7.*INTO#VT8FROM#VT7OrderBy#VT7.Customer
SELECT*FROM#VT8
--返回2行数据,经过排序
--这个查询结束演示。完整的8个步骤
仔细看看,是不是我们需要的结果呢?
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
相关文章推荐
- T-SQL查询的逻辑工作原理
- T-SQL查询的逻辑工作原理
- SQL逻辑查询语句执行顺序
- SQL逻辑查询处理顺序
- T-SQL查询进阶--基于列的逻辑表达式
- 【个人学习4之--SQL中逻辑查询处理的各个阶段】
- sql查询原理和Select执行顺序
- T-SQL查询-逻辑查询处理
- sql语句中较为重要的查询逻辑
- SQL逻辑查询解析
- 数据有内在逻辑的表sql查询
- SQL语句内部逻辑查询的执行顺序
- 应用程序的SQL查询原理
- SQL 语句查询Exists原理
- 理解SQL查询的底层原理
- 个人学习4之--SQL中逻辑查询处理的各个阶段
- SQL逻辑查询语句执行顺序
- SQL查询原理
- SQL 物理查询原理(上)
- SQL查询的逻辑执行顺序,来自技术内幕