当前位置: 首页 > 科技观察

MySQL让人对多表查询又爱又恨

时间:2023-03-12 02:27:34 科技观察

1、前言在SQL开发中,多表联合查询是绝对绕不开的技能。同一个查询结果的不同写法,其运行效率是不同的。在实际开发中,见过(我好像写过~)很多又长又臭的查询SQL,查个十几分钟的数据量是家常便饭。所以,如果深入了解SQL的多表查询机制,少写一些慢查询,应该可以避免挨骂。2.等价连接和非等价连接2.1等价连接等价连接是多表查询中最基本、最简单的一种,它的值是所有满足条件的笛卡尔积。from之后,会先出现前面结果写到哪个表的值,如下:select*fromstudent,familywherestudent.family_id=family.id;阿里在最新的Java开发手册中规定,只要涉及到多个表,就必须在列名前加上表的别名(或表名)来限制。2.2非等价连接非等价连接是通过表a中的值在表b中一定范围内进行的,可以很好的满足预设的切分统计要求。非等价连接有两种写法,使用between...and...orgreaterthansignlessthansign--第一种写法:使用between...and...selecta.discipline_name,a.score,b.grade_tagfromachievementa,achievement_gradebwherea.scorebetweenb.lowest_scoreandb.highest_score;--第二种写法,使用>=或<=selecta.discipline_name,a.score,b.grade_tagfromachievementa,achievement_gradebwherea.score>=b.lowest_scoreanda.score<=b.highest_score;3.自连接与非自连接3.1自连接自连接,顾名思义,就是同一张表自己连接起来。为了区分,需要给表格起不同的别名。比如一个score表,需要查询所有比“Chinese”高的数据:如果不使用self-join,需要先查询Chinesescore,再查询大于的数据这个分数。具体可以按照以下步骤查询:--首先查询语言selectscorefromachievementwherediscipline_name='language'的分数;--然后查询得分高于语言得分的数据select*fromachievementwherescore>76;并使用self连接,一条sq语句即可完成查询:selecta.*fromachievementa,achievementbwhereb.discipline_name='language'anda.score>b.score;3.2非自连接除了自连接,其他的都叫非自连接~~~4。内连接和外连接区分内连接和外连接本质上是另一种分类方法,比如内连接就是等价连接。内连接:合并具有相同列的两个或多个表的行,并且结果集中不包含一个表与另一个表不匹配的行。外连接:在连接过程中,两表除了返回左(或右)表中不满足条件的行外,还返回满足连接条件的行,这种连接称为左(或右)外连接.当没有匹配的行时,结果表中对应的列为空(NULL)。左外连接:连接条件中左边的表也称为主表,右边的表称为从表。右外连接:连接条件中右边的表也称为主表,左边的表称为从表。Fullouterjoin4.1测试数据学生表student和家庭表family的测试数据如下:4.2Leftouterjoin--找出student中的所有数据,不满足的显示为null--这里的student前面是selecteda.*fromstudentaleftjoinfamilybona.family_id=b.id4.3rightouterjoin--找出student中的所有数据,不满足则显示为null--这里学生将选择a.*fromfamilybrightjoinstudentaonb.id=a.family_id;4.4全外连接不幸的是,MySQL不支持全外连接。附:测试数据SQL脚本--自动生成定义createtablestudent(idintauto_incrementprimarykey,student_idintnullcomment'学号',student_namevarchar(40)nullcomment'姓名',family_idintnullcomment'家庭ID',create_timedatetimedefaultCURRENT_TIMESTAMPnullcomment'创建时间')comment'学生表';createtablefamily(idintauto_incrementprimarykey,family_namevarchar(40)nullcomment'familyname',family_addressvarchar(40)nullcomment'家庭地址',create_timedatetimedefaultCURRENT_TIMESTAMPnullcomment'creationtime')comment'familytable';createtableachievement(idintauto_increment主键,scoreintnullcomment'score',discipline_namevarchar(40)nullcomment'学科名称',student_idintnullcomment'学号')comment'结果';createtableachievement_grade(idintauto_incrementprimarykey,grade_tagvarchar(10)nullcomment'grade',lowest_scoreintnullcomment'最低分',highest_scoreintnullcomment'最高分',create_timedatetimedefaultCURRENT_TIMESTAMPnullcomment'创建时间')comment'Scoregradetable';INSERTINTOachievement_grade(id,grade_tag,lowest_score,highest_score,create_time)VALUES(1,'失败',0,60,'2022-03-0211:44:01');INSERTINTOachievement_grade(id,grade_tag,lowest_score,highest_score,create_time)VALUES(2,'good',60,80,'2022-03-0211:44:01');INSERTINTOachievement_grade(id,grade_tag,lowest_score,highest_score,create_time)VALUES(3,'优秀',80,100,'2022-03-0211:44:01');INSERTINTOstudent(id,student_id,student_name,family_id,create_time)VALUES(1,1,'张三',1,'2022-03-0209:55:01');插入INTOstudent(id,student_id,student_name,family_id,create_time)VALUES(2,2,'李四',2,'2022-03-0209:55:01');INSERTINTOstudent(id,student_id,student_name,family_id,create_time)VALUES(3,3,'王五',3,'2022-03-0209:55:01');INSERTINTOstudent(id,student_id,student_name,family_id,create_time)VALUES(4,4,'高飞',null,'2022-03-0219:45:14');INSERTINTOfamily(id,family_name,family_address,create_time)VALUES(1,'张三家','北京','2022-03-0209:54:13');INSERTINTOfamily(id,family_name,family_address,create_time)VALUES(2,'李四家','上海','2022-03-0209:54:13');INSERTINTOfamily(id,family_name,family_address,create_time)VALUES(3,'王五家','西伯利亚','2022-03-0209:54:13');INSERTINTOachievement(id,score,discipline_name,student_id)VALUES(1,76,'语文',1);INSERTINTOachievement(id,score,discipline_name,student_id)VALUES(2,80,'数学',1);INSERTINTOachievement(id,score,discipline_name),student_id)VALUES(3,65,'英语言',1);INSERTINTOachievement(id,score,discipline_name,student_id)VALUES(4,98,'地理',1);INSERTINTOachievement(id,score,discipline_name,student_id)VALUES(5,77,'历史',1);INSERTINTOachievement(id,score,discipline_name,student_id)VALUES(6,69,'生物',1);