mysql笛卡尔积 去重_mysql,SQL标准,多表查询中内连接,外连接,自然连接等详解之查询结果集的笛卡尔积的演化...

本文详细介绍了MySQL中的连接查询,包括如何避免笛卡尔积,使用WHERE子句去重,以及内连接、外连接(左连接、右连接)和自然连接的使用方法。通过实例解析了不同连接类型的执行过程和结果,帮助理解如何在SQL查询中有效地组合和过滤数据。
摘要由CSDN通过智能技术生成

SELECT tname,dname,cname,ctest from teacher,course WHERE teacher.cno=course.cno

c70fe260bd2186fcfb88b590c6d3d13f.png

该语句的执行过程实例可以表示这样:

a,系统首先执行from子句,这里from子句列出有两个表teacher表和course表,DBMS讲计算这两个表的笛卡尔积,列出这两个表中行的所以可能组合,形成一个中间表。中间表中的每条记录包含了两个表中的所有行。

b,然后系统执行where子句,根据teacher.cno=course.cno关系对中间表进行搜索,去除那些不满足该关系的记录。

c,最后系统执行select语句,从执行where子句后得到的中间表的每条记录中,提取tname,dname,cname,ctest4个字段的信息作为结果表。

需要强调,表的连接所依据的关系是在where子句中定义的。在实际应用中,用户要实现表的连接必然要依据一定的关系。

如果不指明连接关系,即不使用where子句。

SELECT tname,dname,cname,ctest from teacher,course

a2d09334ccf0786e6ec25b04797b5c97.png

从结果可以看到,每个教师的信息均与所有课程信息进行了匹配连接。它实际返回连接表中所有数据行的笛卡尔积,其结果集合中的数据行数等于第一个表中符合查询条件的数据行乘以第二个表中符合查询条件的数据行数,即10X11=110条记录。

采用join关键字建立连接

也可以在from子句中,通过连接关键字实现表的连接,这样有助于将连接操作与where的搜索条件区分开来。

SELECT COLUMN from join_table join_type join_table on (join_condition)

join_type为连接类型,可分为4种:自然连接,内连接,外连接和交叉连接。

自连接

自连接是指表与其自身进行连接,这需要使用表别名。

查询成绩中存在不及格课程的学生的姓名,所在系,所有的课程及成绩信息。

SELECTs.sname,s.dname,s.cno,s.markfromstudent swhere s.mark<60

e51e74214be5fa3550820c966e4eb9b0.png

无法得到想要结果

SELECTs.sname,s.dname,s.cno,s.markfromstudent swhere s.sno in(SELECT DISTINCT s.sno from student s where s.mark<60)

08fd6a5fb74812b2a3ec0493a9e1c127.png

得到想要结果

SELECT DISTINCTs.sname,s.dname,s.cno,s.markfromstudent s,student s2where s.sno=s2.snoand s2.mark<60

3d480d9b837a684e62b944e40659d556.png

from子句中的两个表实际上都是表student。为了独立地使用它们,采用表别名方法。

SELECTs.sname,s.dname,s.cno,s.markfromstudent s,student s2where s.sno=s2.snoand s2.mark<60

34b3bbf803c828b21140ef4249c60b5b.png

系统首先执行from子句,将student表S1与它自身S2的笛卡尔积,作为中间表。

实际上,该中间表的每一条记录包含两部分信息,一部分是S1的记录,一部分是S2的记录。而后执行where子句,在中间表中,搜索S2中成绩低于60的学生的记录,同时要求记录中S1与S2是同一个学生的记录即学号相同。最后执行select语句,从中间表获取S1中相应的信息作为结果表。

当执行where子句,从中间表中逐条搜索S2中成绩低于60的学生的记录时,由于孙庆有两门课程不及格,所以对每门不及格的记录都满足搜索条件,因此导致从S1得到的信息中出现了重复的记录。

简单来说,中间表是没有重复记录的,但是S1部分字段是有重复的,而结果集提取的只是S1部分的字段,因此就有可能有重复记录。

一般情况,自连接也可以使用子查询的方式实现。

SELECT DISTINCTs.sname,s.dname,s.cno,s.markfromstudent s,student s2where s.sno=s2.snoand s.mark<60

5a9ffefe00a901c88c5e4bc626d0ac5c.png

自然连接

它将表中具有相同名称的列自动进行记录匹配,自然连接不必指定任何同等连接条件。

ac3d938fb56041e2e4bcf1937aa74ead.png

自然连接自动判断相同名称的列,而后形成匹配。缺点是,虽然可以指定查询结果包括哪些列,但是不能人为地指定哪些列被匹配。另外,自然连接的一个特点是连接后的结果表中匹配的列只有一个。如上,在自然连接后的表中只有一列C。

从student表和teacher表中查询学生姓名,所在系,所修的本系教师开设的课程的课程号以及开课教师姓名。这时候就采用natural join对两个表进行自然连接。

SELECTsname,dname,cno,tnamefrom student NATURAL join teacher

等价

SELECTsname,s.dname,s.cno,tnamefromstudent s, teacher twhere s.dname=t.dnameand s.cno=t.cno

2136bb2dadb37de67a12898aee1d9490.png

事实上,使用基于where子句的等值连接要比使用natural join运算符进行自然连接要灵活的多。

正如前面介绍的,使用natural join运算符自动判断出具有相同名称的列,而后形成匹配,不能人为地指定哪些列被匹配。当自然连接student和teacher表时,CNO和dname列同时被匹配,而不能只匹配一列。

外连接

不管是内连接还是带where子句的多表查询,都组合自多个表,并生成结果表。换句话说,如果任何一个源表中的行在另一个源表中没有匹配,DBMS将把该行放在最后的结果表中。

而外连接告诉ODBC生成的结果表,不仅包含符合条件的行,而且还包含左表(左外连接时),右表(右外连接时)或两个边接表(全外连接)中所有的数据行。

SQL的外连接共有三种类型:左外连接,右外连接,全外连接。

1,左外连接

左外连接,left outer join ,告诉DBMS生成的结果表中,除了包括匹配行外,还包括join关键字(from子句中)左边表的不匹配行。

左外连接实际可以表示为:

左外连接=内连接+左边表中失配的元组。

其中,缺少的右边表中的属性值用null表示。如下:

1e1f8e0f32d474d26e8022b430bd6004.png

SELECTs.sno,sname,s.cno,cname,ctest,markfrom student s LEFT JOINcourse con s.cno=c.cnoORDER BY sname

2fec641481775162f4f526f1ec6bdcd3.png

右外连接

右外连接,right outer join ,告诉DBMS生成的结果表中,除了包括匹配行外,还包括join关键字(from子句中)右边表的不匹配行。

右外连接实际可以表示为:

右外连接=内连接+右边表中失配的元组。

其中,缺少的左边表中的属性值用null表示。如下:

2164e6f0f4521a1b26c83fa8005e7054.png

SELECTs.sno,sname,s.cno,cname,ctest,markfrom student s RIGHT JOINcourse con s.cno=c.cnoORDER BY sname

db242e525f227381f43037277aff52c6.png

全外连接

全外连接,full outer join,告诉DBMS生成的结果表中,除了包括匹配行外,还包括join关键字(from子句中)左边表和右边表的不匹配行。

可以这样表示:

全外连接=内连接+左边表中失配的元组+右边表中失配的元组

05f6078b90121e78fe869754b651b949.png

SELECTs.sno,sname,s.cno,cname,ctest,markfrom student s full OUTER JOINcourse con s.cno=c.cnoORDER BY sname

本人使用mysql数据库,因为mysql暂时还不支持全外连接full的功能.

一些语句流程顺序,等我有空回顾在写把。等我。勿急躁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值