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='玩具'
)
相关文章推荐
- 14、SQL Server 使用子查询和CTE提供数据之相关子查询
- 12、SQL Server 使用子查询和CTE提供数据
- 13、SQL Server 使用子查询和CTE提供数据之简单子查询
- NHibernate初学者指南(15):使用LINQ to NHibernate提供程序查询数据
- 解决在mybatis中使用CTE进行oracle查询数据类型为long的字段出现流关闭问题
- 使用CTE来实现一条查询丢失的数据行问题
- asp.net查询数据库时提示使用的sql server版本不支持数据类型date
- 使用SQL SERVER 2005/2008 递归CTE查询树型结构
- SQL Server 查询使用Linked Server查询其它数据库服务器的数据
- SQL Server 2012使用Offset/Fetch Next实现分页数据查询
- SQL Server 系统表使用-查询指定数据库中用户表及其列、数据类、长度
- Sql Server 存储过程中查询数据无法使用 Union(All)
- 使用SQL语句查询形成环路的关系数据
- 如何在SQL Server 2005数据库查询中使用CTE
- 请使用PL/SQL来按父子层次关系查询出表的所有数据
- Atitit.mysql oracle with as模式临时表模式 CTE 语句的使用,减少子查询的结构性 mssql sql server..
- Atitit.mysql oracle with as模式临时表模式 CTE 语句的使用,减少子查询的结构性 mssql sql server..
- sql server 通过列之间的数据关系,查询出主从关系
- 【SQL Server】递归CTE查询view/sp/fun中使用的所有表
- Sql Server 存储过程中查询数据无法使用 Union(All)