您的位置:首页 > 数据库

15、SQL Server 使用子查询和CTE提供数据之关系除

2013-05-30 21:56 267 查看

使用子查询和CTE提供数据之关系除

前面有讨论过交叉联接是关系乘法---将两个数据集相乘得到笛卡尔乘积。

从理论上来说,所有联接都是有限制的交叉联接,如内联接就是从两个数据集的关系乘积

中选取关键键值匹配的行。

一、关系除与关系乘、联接之间的关系以及关系除的种类

关系除与关系乘之间是互补。如果知道了笛卡尔乘积和一个乘数数据集,使用关系除

就可以推断出另一个乘数集。

有两个关系除:1、带余数的关系除 2、关系整除

一个经典的关系除示例是:哪些学生通过了所有必修课。

关系整除查询:只列出通过了所有必修课的学生。

带余数的关系除查询(也称为近似除):不仅列出所有通过了必修课的学生,还列出了通过

其他课程的学生。

联接/子查询和关系除用来解决不同类型的问题,下面是一些示例:

1、使用联接/子查询解决

Q1:谁参加过旅行团?

Q2:谁居住在营地所在的地区?

Q3:谁在其居住地参加了活动?

2、关系整除

Q1:谁参加过其居住州的每个旅行团,但没有参加过任何其他旅行团?

Q2:谁购买了每种风筝,但未购买任何其他商品?

Q3:哪些妇女(已离异)嫁过同一个男人,但没有同其他男人结过婚?

3、带余数的关系除

Q1:谁参加了其所在州的每个旅行团,且可能参加过其他旅行团?

Q2:谁购买过每种风筝,且可能购买过其他商品?

Q3:哪些妇女(已离异)嫁过同一个男人,且可能同其他男人结过婚?

二、编写关系除查询的方法

至少可以使用两种方法来编写关系除查询。

1、使用嵌套的相关子查询来查找属于或不属于集合的行

2、比较被除数和除数数据集的行数(更为直接且常用)

:谁至少购买了OBXKites销售的每种一玩具中的一个。

三、带余数的关系除 实例

谁购买的玩具的种类数等于商店销售的玩具种类数

Select Contact.ContactCode 联系人联系方式  from Contact

inner join Order on Contact.ContactID=Order.ContactID

inner join OrderDetail on Order.OrderID=OrderDetail.OrderID

inner join Product on OrderDetail.ProductID=Product.ProductID

inner join ProductCategory on Product.ProductCategoryID=ProductCategory.ProductCategoryID

where ProductCategory.ProductCategoryname='玩具'

group by Contact.ContactCode

having Count(distinct  Product.Code)=

(

select count(ProductCode) from Product 

inner join PrductCategory on Product.ProductCategoryID=ProductCategory.ProductCategoryID

where ProductCategory.ProductCategoryname='玩具'

)

注:这里使用的聚合函数是对根据不同的联系人分组后进行统计(必须消除重复行,因为

可能买了多个同类的玩具。如果不消除重复行,就不能计算实际的种类数),

这里的结果集包括满足指定条件外(只买了条件指定的商品的客户)还包含其他数据的行

(除了条件指定的商品,还购买了其它商品的客户),较关系整除更为有用。

四、关系整除 实例

采用更为严格的条件,得到的结果中不包含会导致余数的行。

上面的问题会变成:谁购买了所有种类的玩具,且没有购买其他商品。

也就是只购买了所有玩具各类的客户。没有其他任何商品的购买。

如:

--购买的商品总种类数

Select Contact.ContactCode 联系人联系方式  from Contact

inner join Order on Contact.ContactID=Order.ContactID

inner join OrderDetail on Order.OrderID=OrderDetail.OrderID

inner join Product on OrderDetail.ProductID=Product.ProductID

inner join ProductCategory on Product.ProductCategoryID=ProductCategory.ProductCategoryID

inner join

 (

--购买的玩具种类总数

Select Contact.ContactCode,Product.Code  from Contact

inner join Order on Contact.ContactID=Order.ContactID

inner join OrderDetail on Order.OrderID=OrderDetail.OrderID

inner join Product on OrderDetail.ProductID=Product.ProductID

inner join ProductCategory on Product.ProductCategoryID=ProductCategory.ProductCategoryID

where ProductCategory.ProductCategoryname='玩具'



as  ToysOrder

on Contact.ContactCode=ToysOrder.ContactCode

group by Contact.ContactCode

--购买的商品总种类

having Count(distinct  Product.Code)=

(

--商品中的玩具种类

select count(ProductCode) from Product 

inner join PrductCategory on Product.ProductCategoryID=ProductCategory.ProductCategoryID

where ProductCategory.ProductCategoryname='玩具'

)

and 

--购买的玩具种类

count(distinct ToysOrder.ProductCode)=

(

--商品中的玩具种类

select count(ProductCode) from Product 

inner join PrductCategory on Product.ProductCategoryID=ProductCategory.ProductCategoryID

where ProductCategory.ProductCategoryname='玩具'

)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: