在深入示例前,我想简单地介绍一下简单的集合概念和本章使用的术语。虽然,我相信你对数学概念中的集合、交集和并集很熟悉,但我更愿意将这些集合代数学术语翻译成现实世界的例子。
2.1.1组件
当讨论集合时,需要知道3种类型的组件。首先是集合本身。集合是由元素组成的,并且,出于我们的目的,元素是数据库表中的一行,或者是查询返回的一行。最后,是全集,它是我们用来表示对于一个给定的集合中所有可能出现的元素的集合的术语。
2.1.1.1集合
集合是由元素组成的。根据定义,元素是不能重复的,并且是不排序的。在这里,集合的数学定义和SQL中实际使用的是不同的。在现实世界中,经常将集合中的元素按指定的顺序排序。这样做可以让你找出极端元素,例如,前5个,最后5个。图2-1展现了2个集合。以后我们讨论集合术语的各个方面时,会提到这些例子。
根据我们的目的,我们将集合认为是由表中的行组成的,这些行是由一个公共元素标识的。例如,考虑下面的订单项表。这个表是由集合组成的,每一个集合都是由一个唯一的订单号标识的。
CREATE
TABLE
OrderItems(
OrderId
INTEGER
,
ItemId
INTEGER
,
ProductId
CHAR
(
10
),
Qty
INTEGER
,
PRIMARY
KEY
(OrderId,ItemId)
)
在这个例子中,每一个集合都代表一个订单,它由几个不重复的元素组成。这些元素会是定义产品和对这些产品排序的数量的行。公共元素是OrderId。
2.1.1组件
当讨论集合时,需要知道3种类型的组件。首先是集合本身。集合是由元素组成的,并且,出于我们的目的,元素是数据库表中的一行,或者是查询返回的一行。最后,是全集,它是我们用来表示对于一个给定的集合中所有可能出现的元素的集合的术语。
2.1.1.1集合
集合是由元素组成的。根据定义,元素是不能重复的,并且是不排序的。在这里,集合的数学定义和SQL中实际使用的是不同的。在现实世界中,经常将集合中的元素按指定的顺序排序。这样做可以让你找出极端元素,例如,前5个,最后5个。图2-1展现了2个集合。以后我们讨论集合术语的各个方面时,会提到这些例子。
![](https://p-blog.csdn.net/images/p_blog_csdn_net/ntwo1980/Transact_SQL_2.1.png)
根据我们的目的,我们将集合认为是由表中的行组成的,这些行是由一个公共元素标识的。例如,考虑下面的订单项表。这个表是由集合组成的,每一个集合都是由一个唯一的订单号标识的。
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
在这个例子中,每一个集合都代表一个订单,它由几个不重复的元素组成。这些元素会是定义产品和对这些产品排序的数量的行。公共元素是OrderId。
集合和主键
主键和定义集合的公共元素之间有什么关系?答案是它们实际上没有任何关系。表中任何一列,或列的组合,都可以认为是一个集合的定义。它实际上就是考虑数据的一种方式。在OrderItems表中,OrderId列是定义一个订单的所有项的公共列。这当然是数据的一个有效视图,但也有其它观察数据的方式。例如,ProductId列,定义了特定产品的项的集合。在现实世界中,你认为的大多数集合更可能对应到你的外键列。
因为可以用多个列定义一个集合,所以这些列中包含表的主键是非常不太可能的。如果这样,每个集合都将只有一条记录。如果你的集合只包含一条记录,你可能应该重新考虑表结构或者表中集合的解释。否则,你可能会在应用本章中演示的例子中遇到麻烦。
使用 SQL,可以很容易地列出一个集合中的元素。你可以简单地使用带有筛选特定集合的WHERE子句的SELECT语句。下面查询返回所有根据条件Order #112筛选的集合中的记录:
SELECT
*
FROM
OrderItems
WHERE
OrderId
=
112
2.1.1.2元素
元素是集合的成员。在表2-1中,每一个字母都是一个元素。在我们的情况中,当使用SQL时,一个元素就是表中的一行。在SQL中,不要将元素想像成统一的实体通常是有好处的。在纯数学术语中,不可能将一集合中的元素分割为两个或更多的组件。然而,在SQL中,你可以将一个元素分割成多个组件。一个表通常由不同的列组成,你通常写的查询只操作这些列的一个子集。
例如,假如你想找出所有包含炸药的订单的集合,而不考虑数量。你的元素是OrderItem表中的行。你需要使用ProductId列标识炸药,你需要返回OrderId列标识订单,但是,你不需要使用表中的其它行。以下是查询:
SELECT
OrderId
FROM
OrderItems o
GROUP
BY
OrderId
HAVING
EXISTS
(
SELECT
*
FROM
OrderItems o1
WHERE
o1.ProductId
=
'
Explosive
'
AND
o.OrderId
=
o1.OrderId)
这个查询实际上使用了你会在本章中读到的集合操作中的其中一个。这个操作就是包含(contains),对应于SQL关键字EXISTS。
2.1.1.3全集
全集是一个给定集合的所有可能元素的集合。考虑图2-1中的集合1和2。每个集合由字母表中的字符组成。如果我们规定只有字母可能是集合元素,这两个集合的全集就会是所有字母的集合,如图2-2所示。
考虑一个更现实的集合全集例子,假设一个学校向它的学生提供40门可能的课程。每个学生在一个学期内选择这40门课程中很少的一部分。课程就是元素。一个学生选取的课程组成一个集合。不同的学生选取不同数量和不同组合的课程。这些集合不会是全都一样的,大小也不会一样,但它们都包含来自同一个全集的元素。每个学生必须从相同的40种可能中选择。
在上面所说的学生/课程例子中,所有集合的所有元素都来自于同一个全集。对于表中的某些集合拥有不同于其它集合的全集也是有可能的。例如,假设有一个包含学生提交的已完成的案例学习的表。进一步假设每一门课程可能的案例学习的全集是不同的。如果你考虑由课程和学生定义的集合,则全集依赖于学生学习的课程。每一个课程都有不同的全集。
2.1.2 集合操作
集合操作允许你使用两个集合并返回某种有意义的结果。准确的结果依赖于执行的操作。例如,你可以使用两个集合,返回在两个集合中都出现的元素。这个操作称作交集。其它的操作包括:包含、并集、补集和差集。
2.1.2.1包含
包含操作告诉你一个特定的元素是否可能在另一个元素中被发现。图2-3演示了集合1(从图2-1来)包含字母“D”。
包含是一个十分基本的集合代数操作,在SQL中可以通过组合SELECT语句和EXISTS子句直接实现。例如,在下面的查询中,EXISTS用来检查StudentMaster表中的每个学生是否也在学习ACCN101课程的学生集合中:
SELECT
*
FROM
StudentMaster sm
WHERE
EXISTS
(
SELECT
*
FROM
Students s
WHERE
sm.StudentName
=
s.StudentName
AND
s.Course
=
'
ACCN01
'
)
EXISTS的使用是如此的普通,因此也许你从来过多得考虑你代表的集合操作。
2.1.2.2交集
SELECT
DISTINCT
StudentName
FROM
Students
WHERE
CourseId
=
'
ACCN101
'
INTERSECT
SELECT
DISTINCT
StudentName
FROM
Students
WHERE
CourseId
=
'
MGMT120
'
交集是对两个或多个集合进行比较以得出公共元素的操作。例如,图2-4演示了集合1和集合2之间的交集。
一个典型的关于交集的问题是哪些学生既学习了ACCN101课程,也学习了MGMT120课程。SQL-92标准指定使用INTERSEC关键字实现交集操作。因此,你可以这样写:
SELECT
DISTINCT
StudentName
FROM
Students
WHERE
CourseId
=
'
ACCN101
'
INTERSECT
SELECT
DISTINCT
StudentName
FROM
Students
WHERE
CourseId
=
'
MGMT120
'
不幸的是,SQL SERVER没有实现INTERSECT关键字。本章的intersection示例将会展示一些处理这个限制的技术。另外,本章将会演示如何执行部分交集。部分交集允许你找出属于特定数量的集合,而不必属于所有集合。
2.1.2.3并集
并集是一个将两个或多个集合组合成一个更大集合的方法,正如图2-5显示的。结果集包含两个集合的所有元素。
SQL(作为一个语言)使用UNION关键字实现并集操作。它允许你使用两个SELECT语句返回的行,并将它们返回到一个结果集中。例如,下面的查询返回学习ACCN101或者MGMT120课程的学生列表:
SELECT
*
FROM
Students
WHERE
CourseId
=
'
ACCN101
'
UNION
SELECT
*
FROM
Students
WHERE
CourseId
=
'
MGMT120
'
在SQL中,并集操作从结果集中移除所有的重复行。联系到这个例子,如果一个学生学习了两门课,他也只会被列出一次。如果你希望保留重复行,你可以使用UNION ALL替代UNION。
当你使用UNION操作符执行SELECT语句时,服务器会分别执行每个查询。在很多情况下,交集可以不通过UNION操作符而更有效地取得。典型的例子就是你可以定义一个WHER就是E子句组合两个集合标识符。另一个例子是对多个集合计算聚合信息。
2.1.2.4补集
补集就是全集中所有的在一个集合中缺少的元素的集合。图2-6显示了集合1和它的补集,相应的全集在图2-2中。
补集操作与集合的全集非常相关。补集和原集合的并集就是原集合的全集。在后面的一个示例中,这样操作的一个例子是搜索一个学生的记录,并生成缺少的学期报告列表。
不要被这个概念的简单误导。使用补集需要定义全集。通常可能使用一个范围定义一个全集,你可以定义一个特殊的拥有100个可能的狭槽的容器。在这个例子中,操作补集是十分容易的。然而,如果你的问题需要明确地指定集合中的每一个可能的元素,补集操作的复杂度就会增加。在这个例子中,你必须定义不同表的全集,然后将这张表连接到你的查询。
2.1.2.5差集
两个集合的差集是在一个集合中,而不在另一个集合中的元素的集合。图2-7举例说明了集合1和集合2 的差集。
集合差集是集合编程中的一个普通问题,当你想找出两个或多个集合之间的差异时,它是很有用的。你可以从一个集合中减去一个集合,从所有集合中减去一个集合,或者从一个集合中减去多个集合。
SQL-92标准指定EXCEPT关键字实现集合差集。不幸的是,就像INTERSECTION,EXCEPT关键字在SQL SERVER中也没有实现。在本章,我会向你演示使用不同的方法生成两个集合间的差集。
因为可以用多个列定义一个集合,所以这些列中包含表的主键是非常不太可能的。如果这样,每个集合都将只有一条记录。如果你的集合只包含一条记录,你可能应该重新考虑表结构或者表中集合的解释。否则,你可能会在应用本章中演示的例子中遇到麻烦。
使用 SQL,可以很容易地列出一个集合中的元素。你可以简单地使用带有筛选特定集合的WHERE子句的SELECT语句。下面查询返回所有根据条件Order #112筛选的集合中的记录:
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
2.1.1.2元素
元素是集合的成员。在表2-1中,每一个字母都是一个元素。在我们的情况中,当使用SQL时,一个元素就是表中的一行。在SQL中,不要将元素想像成统一的实体通常是有好处的。在纯数学术语中,不可能将一集合中的元素分割为两个或更多的组件。然而,在SQL中,你可以将一个元素分割成多个组件。一个表通常由不同的列组成,你通常写的查询只操作这些列的一个子集。
例如,假如你想找出所有包含炸药的订单的集合,而不考虑数量。你的元素是OrderItem表中的行。你需要使用ProductId列标识炸药,你需要返回OrderId列标识订单,但是,你不需要使用表中的其它行。以下是查询:
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
这个查询实际上使用了你会在本章中读到的集合操作中的其中一个。这个操作就是包含(contains),对应于SQL关键字EXISTS。
2.1.1.3全集
全集是一个给定集合的所有可能元素的集合。考虑图2-1中的集合1和2。每个集合由字母表中的字符组成。如果我们规定只有字母可能是集合元素,这两个集合的全集就会是所有字母的集合,如图2-2所示。
![](https://p-blog.csdn.net/images/p_blog_csdn_net/ntwo1980/Transact_SQL_2.2.png)
考虑一个更现实的集合全集例子,假设一个学校向它的学生提供40门可能的课程。每个学生在一个学期内选择这40门课程中很少的一部分。课程就是元素。一个学生选取的课程组成一个集合。不同的学生选取不同数量和不同组合的课程。这些集合不会是全都一样的,大小也不会一样,但它们都包含来自同一个全集的元素。每个学生必须从相同的40种可能中选择。
在上面所说的学生/课程例子中,所有集合的所有元素都来自于同一个全集。对于表中的某些集合拥有不同于其它集合的全集也是有可能的。例如,假设有一个包含学生提交的已完成的案例学习的表。进一步假设每一门课程可能的案例学习的全集是不同的。如果你考虑由课程和学生定义的集合,则全集依赖于学生学习的课程。每一个课程都有不同的全集。
2.1.2 集合操作
集合操作允许你使用两个集合并返回某种有意义的结果。准确的结果依赖于执行的操作。例如,你可以使用两个集合,返回在两个集合中都出现的元素。这个操作称作交集。其它的操作包括:包含、并集、补集和差集。
2.1.2.1包含
包含操作告诉你一个特定的元素是否可能在另一个元素中被发现。图2-3演示了集合1(从图2-1来)包含字母“D”。
![](https://p-blog.csdn.net/images/p_blog_csdn_net/ntwo1980/Transact_SQL_2.3.png)
包含是一个十分基本的集合代数操作,在SQL中可以通过组合SELECT语句和EXISTS子句直接实现。例如,在下面的查询中,EXISTS用来检查StudentMaster表中的每个学生是否也在学习ACCN101课程的学生集合中:
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
EXISTS的使用是如此的普通,因此也许你从来过多得考虑你代表的集合操作。
2.1.2.2交集
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
交集是对两个或多个集合进行比较以得出公共元素的操作。例如,图2-4演示了集合1和集合2之间的交集。
![](https://p-blog.csdn.net/images/p_blog_csdn_net/ntwo1980/Transact_SQL_2.4.png)
一个典型的关于交集的问题是哪些学生既学习了ACCN101课程,也学习了MGMT120课程。SQL-92标准指定使用INTERSEC关键字实现交集操作。因此,你可以这样写:
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
不幸的是,SQL SERVER没有实现INTERSECT关键字。本章的intersection示例将会展示一些处理这个限制的技术。另外,本章将会演示如何执行部分交集。部分交集允许你找出属于特定数量的集合,而不必属于所有集合。
2.1.2.3并集
并集是一个将两个或多个集合组合成一个更大集合的方法,正如图2-5显示的。结果集包含两个集合的所有元素。
![](https://p-blog.csdn.net/images/p_blog_csdn_net/ntwo1980/Transact_SQL_2.5.png)
SQL(作为一个语言)使用UNION关键字实现并集操作。它允许你使用两个SELECT语句返回的行,并将它们返回到一个结果集中。例如,下面的查询返回学习ACCN101或者MGMT120课程的学生列表:
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
在SQL中,并集操作从结果集中移除所有的重复行。联系到这个例子,如果一个学生学习了两门课,他也只会被列出一次。如果你希望保留重复行,你可以使用UNION ALL替代UNION。
当你使用UNION操作符执行SELECT语句时,服务器会分别执行每个查询。在很多情况下,交集可以不通过UNION操作符而更有效地取得。典型的例子就是你可以定义一个WHER就是E子句组合两个集合标识符。另一个例子是对多个集合计算聚合信息。
2.1.2.4补集
补集就是全集中所有的在一个集合中缺少的元素的集合。图2-6显示了集合1和它的补集,相应的全集在图2-2中。
![](https://p-blog.csdn.net/images/p_blog_csdn_net/ntwo1980/Transact_SQL_2.6.png)
补集操作与集合的全集非常相关。补集和原集合的并集就是原集合的全集。在后面的一个示例中,这样操作的一个例子是搜索一个学生的记录,并生成缺少的学期报告列表。
不要被这个概念的简单误导。使用补集需要定义全集。通常可能使用一个范围定义一个全集,你可以定义一个特殊的拥有100个可能的狭槽的容器。在这个例子中,操作补集是十分容易的。然而,如果你的问题需要明确地指定集合中的每一个可能的元素,补集操作的复杂度就会增加。在这个例子中,你必须定义不同表的全集,然后将这张表连接到你的查询。
2.1.2.5差集
两个集合的差集是在一个集合中,而不在另一个集合中的元素的集合。图2-7举例说明了集合1和集合2 的差集。
![](https://p-blog.csdn.net/images/p_blog_csdn_net/ntwo1980/Transact_SQL_2.7.png)
集合差集是集合编程中的一个普通问题,当你想找出两个或多个集合之间的差异时,它是很有用的。你可以从一个集合中减去一个集合,从所有集合中减去一个集合,或者从一个集合中减去多个集合。
SQL-92标准指定EXCEPT关键字实现集合差集。不幸的是,就像INTERSECTION,EXCEPT关键字在SQL SERVER中也没有实现。在本章,我会向你演示使用不同的方法生成两个集合间的差集。