SQL Server 2005 技术内幕 TSQL查询学习笔记chapter4之一子查询Subqueries

用到的数据库NorthWind

http://www.microsoft.com/downloads/details.aspx?FamilyID=06616212-0356-46a0-8da2-eebc53a68034&DisplayLang=en

1:标量子查询(相对于多值子查询)

只有标量子查询返回的是单个记录或者不返回,就是有效的子查询。

Ex1:select OrderId From Orders where EmployeeId=

(select EmployeeId From employees where lastName like N'Davolio')

’Davolio’改为'D%',这个时候子查询中返回结果为2,等号右边此时为多值,查询失败.’=’改为in谓词.查询才能通过.

employees表中无lastname=’jason’,外部查询将返回null.

2:独立子查询(相对于相关子查询)

Ex2:返回每个美国员工至少为其处理过订单的所有客户

--思路:1:Employees表中获取美国员工总数2:Orders表中查询美国员工处理的Order,CustomerID分组后,统计其不同的EmployeeID正好等于美国员工总数

Select CustomerID From Orders Where EmployeeID In

(Select EmployeeID From Employees Where Country=N'USA')

group by CustomerID

Having Count(Distinct EmployeeID)=

(Select Count(*) From Employees Where Country=N'USA')--美国员工总数

Ex3:返回在每月最后实际订单日期发生的订单(每月最后订单日期可能不是每月最后一天)

--思路:子查询按月分组得到每月最近订单日期

Select OrderID,CustomerID,EmployeeID,OrderDate

From Orders

Where OrderDate In

(Select Max(OrderDate) From Orders Group by Convert(char(6),OrderDate,112))--112表示YYYYMMDD char(6)提取YYYYMM

3:相关子查询

引用外部查询列的子查询。逻辑上讲,子查询会为外部查询的每行计算一次。

Ex4:查询每个员工employee最近的一个订单

思路:--需要附加属性(Tiebreaker)Max(OrderDate)最大订单日期和Max(OrderId)最大订单号来确定每名员工的最近订单状况

select OrderId,CustomerId,EmployeeId,OrderDate From Orders As o1 where OrderDate=

(

    select Max(OrderDate) From Orders As o2 where o2.EmployeeId=o1.EmployeeId--得到每名员工的最近订单日期

)

and OrderId=

(

    select Max(OrderId) From Orders As o2 Where o2.EmployeeId=o1.EmployeeId and o2.OrderDate=o1.OrderDate--得到每名员工每个订单日期的最大OrderId

)

4:Exists()谓词

输入一个查询,是否产生行,返回TrueFalse,不返回Unknown。查询中带*不是一个好的习惯,但Exists查询语句中可以使用。它只关心返回行,优化器忽略查询中的列表

Ex5:返回来自Spain国家且发生过订单的Customer

Select CustomerID,CompanyName From Customers AS c

Where Country=N'Spain' And

Exists(Select * From Orders AS o Where o.CustomerID=c.CustomerID )

--In版本

Select CustomerID,CompanyName From Customers AS c

Where Country=N'Spain' And

CustomerID In(Select CustomerID From Orders)

Not ExistsNot In的区别(ExistsIn区别不大,产生相同执行计划)

Not In(当存在Null的时候)是不返回记录的,所以要去掉Null的情况,将和Not

Exists产生相同查询结果。但Not In 查询计划会关心列为Null的情况,所以Not Exists性能更好点

Select CustomerID,CompanyName From Customers AS c

Where Country=N'Spain' And CustomerID

NOt In(Select CustomerID From Orders where CustomerID is not Null )

5:行为不当的子查询

当子查询中有无效列的情况

首先运行

use tempdb

create table Orders

(

    OrderID int not null identity(1,1),

    ClientID int not null

)

Create table Customers

(

    CustomerID int not null identity(1,1),

    CustomerName varchar(5) not Null

)

insert into Customers (CustomerName) values('jason')

insert into Customers (CustomerName) values('mary')

insert into Orders (ClientID) values(1)

insert into Orders (ClientID) values(1)

顾客表:                        订单表:

任务:返回没有定过货的顾客

先运行如下语句

Select CustomerID from Customers where

CustomerID not in(select CustomerID from Orders )注意:CustomerID不属于OrderID

返回一个空集,不会报错。因为名称解析的时候进行从内部向外的过程,这里子查询未查询到列CustomerID,它将在Customers中查找且找到了列为了避免这样的情况发生,好的习惯是子查询中总是为所有的列加上别名,正确的写法如下

Select CustomerID from Customers where

CustomerID not in(select o.ClientID from Orders AS o )

posted @ 2009-10-25 21:58  老Z  阅读(531)  评论(2编辑  收藏  举报