select语句多表联合查询(三)上

版权声明:未经博主允许请勿转载 https://blog.csdn.net/hlz_12345/article/details/84971281

(所有表都在select语句多表联合查询(一)中)

(NOT) in子查询

我们从以下几个问题来展开对In的理解与研究:

1. 如何理解In操作?

2.何时用In操作?

3.如何理解NOT IN 以及何时用NOT IN?

来,我们先来看个简单示例:

select * from Student where Sname in ('张三','王三');

通过执行这条select语句我们会发现,结果表里的就是张三和王三的学生信息。不难发现,张三和王三都是Sname,难道in后面跟的是一个Sname的集合?我们只是在Student表里去寻找Sname为张三或王三的元组,是这样的嘛?我们可以做这样一个查询:

select * from Student where Sname in ('张三','王三',19);

当你去执行这条语句时就发现执行出错了,下方结果会显示在将 varchar 值 '张三      ' 转换成数据类型 int 时失败。这意思好像是在把‘张三’做int类型的强制转换,事实上,就算你把‘张三’,‘王三’改为int也是通不过的,一定要符合Sname的数据类型才能通过,这说明了in后面跟着的确实是前面那个属性的集合。另外,in的操作过程我猜想是程序会在Student表中依次遍历Sname属性值来看是否存在于in后面的那个集合中,如果存在就挑选出来。

示例二:列出选修了‘001’号课程的学生的学号和姓名

首先来思考下用之前学过的东西该怎么写这条查询。这个示例里有课号,学号和姓名,课号学号存在于SC表中,学号姓名存在于Student表中,我们将二表笛卡儿积通过S#连接,再去寻找课号为‘001’的学生。

select Student.S#,Student.Sname from SC,Student where SC.S# = Student.S# AND SC.C# = '001';

好,我们现在试着看看能否用in子查询来完成。我们是否可以理解为我们要去student表里去寻找学号满足某些条件的元组,然后把它的学号和姓名显示出来,即select S#,Sname from Student where S# in 某些条件;而这个"某些条件"就是你要写的select子查询,查询的结果就是In后面的集合。但前提是这个子查询的表里必须包含In前面的那个属性,这样才能将多表连接起来(其实这个也相当于通过共同属性连接了)。比如说这里的"S#",那么我后面的子查询的结果一定是学号的集合,这样才能符合in操作。好,回到“某些条件”,那么学号要满足哪些条件呢?是的,与该学号关联的选修课程为‘001’,我们自然而然地想到了SC表,于是我们可以将子查询写为select S# from SC where C# = '001';把这个语句代入“某些条件”就OK了。

select S#,Sname from Student where S# in (select S# from SC where C# = '001');

不知道大家有没有发现,in子查询就避免了多表笛卡儿积的操作,我猜想在表比较少的情况下,用In子查询会比Θ等值连接更方便,而在多表情况下,等值连接反而更方便(试想下三表以上的in子查询。。),但无论是等值连接还是in子查询,表与表之间一定会有一项共同属性用作连接的桥梁。

示例三:求既学过‘001’号课程又学过‘002’号课程的学生学号。

不得不承认,我的理解不是很到位,我在试着用上面分析的思路来写这道题的时候出错了,但思路就是不断完善的过程啊。来,根据题目我们要在SC表里寻找课程号满足某种条件的学生号,select S# from SC where C# in 某些条件;这个某些条件是否可以写成一个包含‘001’,‘002’的集合呢?当然可以,但是你要知道一个C#只能等于一个值,in也不例外,就拿这个例子来说,where C# in ('001','002'),找到一个C# 等于‘001’的为一条记录,找到为‘002’的为一条记录,并不是找‘001’和‘002’的。所以这样的select结果是选修了001,或002,或都有的学号,并不是我们想要的。

那条件是select C# from SC where C# = '001' and C# ='002'嘛,也不是,出现了二义性。回想一下,我们上一次做这道题时是用什么方法避开了二义性的,对,我们拿了两张SC表做了笛卡儿积并通过S#连接,然后去找第一张里的C#为‘001’,第二张里的为‘002’的元组。要避开二义性,必然要用到两张SC表,那么第一张要满足C#为‘001’,第二张满足C#=‘002’,也就是说我们在第一张SC表里去寻找C#为‘001’且。。的学号,这里我们遇到一个问题,两表用什么连接,仿照等值连接法我们应拿S#做连接,可是原因呢?SC表有两个连接的桥梁,分别是S#和C#,试想一下用C#来做桥梁是否又产生了二义性了呢?所以我们用S#做连接,条件为C# = ‘002’,终于,我们可以把这道题写出来了:

select S# from SC where C# = '001' and S# in (select S# from SC where C# = '002');

//select S# from SC where C# = '001' and C# in (select C# from SC where C# = '002');这条是错误的,C#产生了二义性

 

 

 

猜你喜欢

转载自blog.csdn.net/hlz_12345/article/details/84971281