2.4.1问题
你想要比较两个集合的行以确定两个集合是否相等。例如,你有十月和十一月的学生表的镜像。现在,你想要比较这两份拷贝。
十月镜像如下:
十一月如下:
2.4.2解决方案
一个方案是将两张表作为两个不同的集合。然后你可以采用“实现集合差集”方法解决这个问题,使用这个方法查询在一张表而不在另一张表中的行。下面的查询会对名为StudentsOct和StudentsNov的表采用此方案:
2.4.3讨论
这是一个有些复杂的查询。然而,它实际上是两个十分相似的SELECT语句的并集。一旦你理解了第一个,你就会理解第二个。第一个UNION中的SELECT语句返回存在于StudentsOct而不在StudentsNov中的行列表。第二个SELECT语句恰恰相反—返回在StudenstNov中而不在StudentsOct中行列表。这两个SELECT语句代表了不同的操作。如果两个表相等,没有SELECT会返回行。
让我们关注SELECT语句的第一部分:
这个SELECT语句获取StudentsOct表中的所有列,根据这些列分组,使用聚合函数COUNT返回每一组中和行数。例如:
使用GROUP BY子句列出StudentOct表中每一列是很重要的。在这个示例中,我们加入了额外的TableName列,所以我们可以很容易地看出行属于哪张表。分组操作的目的是处理重复行。如果StudentsOct表有两个相同的行,那么StudentsNov表就必须有两个相同的行相匹配。解决这个问题的唯一方法根据表中的所有行进行分组,计算每个分组中出现的次数,然后在两张表间比较这些次数。
Having子句和WHERE子句一样,但是在分组级别。对于一个表中的每个分组,
你想要比较两个集合的行以确定两个集合是否相等。例如,你有十月和十一月的学生表的镜像。现在,你想要比较这两份拷贝。
十月镜像如下:
CourseId StudentName Score TermPaper
-- ------------------ -------------- ------ -----------
ACCN101 Andrew 11.00 3
-- ------------------ -------------- ------ -----------
ACCN101 Andrew 11.00 3
十一月如下:
CourseId StudentName Score TermPaper
-- ------------------ ------------- ------ -----------
ACCN101 Andrew 11.00 3
ACCN101 Andrew 11.00 3
ACCN101 Bert 13.40 1
-- ------------------ ------------- ------ -----------
ACCN101 Andrew 11.00 3
ACCN101 Andrew 11.00 3
ACCN101 Bert 13.40 1
2.4.2解决方案
一个方案是将两张表作为两个不同的集合。然后你可以采用“实现集合差集”方法解决这个问题,使用这个方法查询在一张表而不在另一张表中的行。下面的查询会对名为StudentsOct和StudentsNov的表采用此方案:
SELECT
so.
*
,
COUNT
(
*
) DupeCount,
'
StudentsOct
'
TableName
FROM StudentsOct so
GROUP BY so.CourseId, so.StudentName, so.Score, so.TermPaper
HAVING NOT EXISTS (
SELECT sn. * , COUNT ( * )
FROM StudentsNov sn
GROUP BY sn.CourseId, sn.StudentName, sn.Score, sn.TermPaper
HAVING sn.CourseId = so.CourseId AND
sn.TermPaper = so.TermPaper AND
sn.StudentName = so.StudentName AND
COUNT ( * ) = COUNT ( ALL so.CourseId))
UNION
SELECT sn. * , COUNT ( * ) DupeCount, ' StudentsNov ' TableName
FROM StudentsNov sn
GROUP BY sn.CourseId, sn.StudentName, sn.Score, sn.TermPaper
HAVING NOT EXISTS (
SELECT so. * , COUNT ( * )
FROM StudentsOct so
GROUP BY so.CourseId, so.StudentName, so.Score, so.TermPaper
HAVING so.CourseId = sn.CourseId AND
so.TermPaper = sn.TermPaper AND
so.StudentName = sn.StudentName AND
COUNT ( * ) = COUNT ( ALL sn.CourseId))
FROM StudentsOct so
GROUP BY so.CourseId, so.StudentName, so.Score, so.TermPaper
HAVING NOT EXISTS (
SELECT sn. * , COUNT ( * )
FROM StudentsNov sn
GROUP BY sn.CourseId, sn.StudentName, sn.Score, sn.TermPaper
HAVING sn.CourseId = so.CourseId AND
sn.TermPaper = so.TermPaper AND
sn.StudentName = so.StudentName AND
COUNT ( * ) = COUNT ( ALL so.CourseId))
UNION
SELECT sn. * , COUNT ( * ) DupeCount, ' StudentsNov ' TableName
FROM StudentsNov sn
GROUP BY sn.CourseId, sn.StudentName, sn.Score, sn.TermPaper
HAVING NOT EXISTS (
SELECT so. * , COUNT ( * )
FROM StudentsOct so
GROUP BY so.CourseId, so.StudentName, so.Score, so.TermPaper
HAVING so.CourseId = sn.CourseId AND
so.TermPaper = sn.TermPaper AND
so.StudentName = sn.StudentName AND
COUNT ( * ) = COUNT ( ALL sn.CourseId))
2.4.3讨论
这是一个有些复杂的查询。然而,它实际上是两个十分相似的SELECT语句的并集。一旦你理解了第一个,你就会理解第二个。第一个UNION中的SELECT语句返回存在于StudentsOct而不在StudentsNov中的行列表。第二个SELECT语句恰恰相反—返回在StudenstNov中而不在StudentsOct中行列表。这两个SELECT语句代表了不同的操作。如果两个表相等,没有SELECT会返回行。
让我们关注SELECT语句的第一部分:
SELECT
so.
*
,
COUNT
(
*
) dupeCount,
'
StudentsOct
'
tableName
FROM StudentsOct so
GROUP BY so.CourseId, so.StudentName, so.Score, so.TermPaper
FROM StudentsOct so
GROUP BY so.CourseId, so.StudentName, so.Score, so.TermPaper
这个SELECT语句获取StudentsOct表中的所有列,根据这些列分组,使用聚合函数COUNT返回每一组中和行数。例如:
CourseId StudentName Score TermPaper DupeCount TableName
-- ---------- ----------- ------ ----------- ----------- -----------
ACCN101 Andrew 11.00 3 1 StudentsOct
...
-- ---------- ----------- ------ ----------- ----------- -----------
ACCN101 Andrew 11.00 3 1 StudentsOct
...
使用GROUP BY子句列出StudentOct表中每一列是很重要的。在这个示例中,我们加入了额外的TableName列,所以我们可以很容易地看出行属于哪张表。分组操作的目的是处理重复行。如果StudentsOct表有两个相同的行,那么StudentsNov表就必须有两个相同的行相匹配。解决这个问题的唯一方法根据表中的所有行进行分组,计算每个分组中出现的次数,然后在两张表间比较这些次数。
Having子句和WHERE子句一样,但是在分组级别。对于一个表中的每个分组,