SQL数据查询实战:在数据海洋中精准捞取所需的艺术
如果说创建表是为数据建造房屋、填充数据是让居民入住那么数据查询就是我们使用数据库时最频繁、最核心、也最激动人心的一项活动。我们辛辛苦苦地把海量数据存进数据库归根结底是为了在需要的时候能够把它们准确地、灵活地取出来加以利用。从浩如烟海的数据中精准地捞取出我们想要的那一部分这正是数据查询的使命也是SQL最为精彩、最见功力的拿手好戏。在SQL这门语言里数据查询全部依靠一个核心的语句来完成这就是大名鼎鼎的 SELECT 语句。SELECT 的本意是选择、挑选这个名字恰如其分地道出了查询的本质那就是从数据中挑选出我们所需要的部分。SELECT 语句功能极其强大变化无穷从最简单的查看整张表到最复杂的多表关联、分组统计都由它来胜任。可以说掌握了 SELECT 语句就掌握了SQL最核心的本领就拥有了在数据海洋中自由遨游、随心捞取的能力。今天我们就来一场数据查询的实战配合一行行具体的代码由浅入深地领略这门在数据海洋中精准捞取所需的艺术。为了演练方便我们沿用之前搭建的学生选课数据库它有三张表学生表 Student包含学号 Sno、姓名 Sname、年龄 Sage、院系 Sdept课程表 Course包含课程编号 Cno、课程名称 Cname、学分 Credit选课表 SC包含学号 Sno、课程编号 Cno、成绩 Grade。下面我们就基于这三张表来展开查询的实战。一、查询语句的基本骨架在动手之前我们先来认识 SELECT 语句的基本骨架。一条完整的查询语句通常由几个部分组成它的基本格式是这样的。SELECT要查询的列FROM要查询的表WHERE筛选的条件;我们来解读这个骨架。开头的 SELECT后面跟着我们想要查看的列也就是回答查什么的问题。接着的 FROM后面跟着数据来自哪张表也就是回答从哪查的问题。然后的 WHERE后面跟着筛选的条件也就是回答查哪些的问题只有满足条件的行才会被选出来。这三个部分SELECT 决定列、FROM 决定表、WHERE 决定行构成了查询语句最基本、最核心的骨架。理解了这个骨架我们就抓住了查询的精髓。下面就让我们从最简单的查询开始一步步往复杂走。二、最简单的查询查看整张表我们先来一个最简单的查询把整张学生表的所有信息都查出来看一看。代码如下。SELECT*FROMStudent;这条语句简短而经典。SELECT 后面的那个星号是一个特殊的符号它表示所有的列。FROM Student 表示数据来自学生表。这条语句没有 WHERE 部分意味着不加任何筛选条件要把所有的行都选出来。所以这条语句的整体意思就是从学生表中选出所有的列、所有的行也就是把整张学生表原原本本地查出来显示给我们看。这就好比我们走进一间档案室把某个柜子里所有的档案全部取出来一份不落地摊在桌上查看。这是最基础、最全面的查询当我们想对一张表的全貌有个整体了解时就可以用它。三、挑选需要的列只看我关心的信息很多时候我们并不需要一张表里所有的列而只关心其中的某几列。这时我们就可以在 SELECT 后面明确地列出我们想要的列名而不是用星号。比如我们只想查看所有学生的学号和姓名代码如下。SELECTSno,SnameFROMStudent;这条语句中SELECT 后面跟着 Sno 和 Sname用逗号隔开表示我们只想要学号和姓名这两列。FROM Student 表示数据来自学生表。这条语句的意思就是从学生表中只选出学号和姓名这两列的所有数据。查询的结果将是一张只包含学号和姓名两列的表至于年龄、院系等其他列则不会出现在结果中。这就好比我们查看档案时只关心每份档案的姓名和编号那就只把这两项信息抄录下来其余的内容暂时不去理会。这种挑选列的查询让我们能够聚焦于自己真正关心的信息使结果更加简洁明了。这在数据库术语里叫做投影意思是从列的方向上对表进行投影选取。四、筛选满足条件的行大浪淘沙查询的真正威力体现在能够根据条件筛选出我们想要的那些行。这就要用到 WHERE 部分了。WHERE 后面跟着一个条件只有满足这个条件的行才会被选出来。这就像大浪淘沙把符合要求的留下不符合的滤掉。比如我们想查出计算机系的所有学生代码如下。SELECT*FROMStudentWHERESdept计算机系;这条语句中WHERE Sdept ‘计算机系’ 就是筛选条件它的意思是院系等于计算机系。这里的等号表示相等的判断计算机系用单引号括起来表示这是一个文字串。这条语句的整体意思就是从学生表中选出院系是计算机系的那些学生的全部信息。只有院系恰好是计算机系的行才会出现在结果里其他院系的学生则被过滤掉。筛选条件还可以是各种各样的比较。比如我们想查出年龄大于二十岁的学生代码如下。SELECTSno,Sname,SageFROMStudentWHERESage20;这条语句中WHERE Sage 20 表示年龄大于二十大于号是一个比较运算。这条语句的意思是从学生表中选出年龄大于二十岁的学生的学号、姓名和年龄。条件还可以更复杂多个条件可以用并且、或者连接起来。比如我们想查出计算机系中年龄小于二十岁的学生代码如下。SELECT*FROMStudentWHERESdept计算机系ANDSage20;这里的 AND 表示并且意思是两个条件必须同时满足。这条语句选出的是既属于计算机系、年龄又小于二十岁的学生。如果把 AND 换成 OR那就表示或者意思是两个条件满足其一即可。通过 WHERE 进行的行筛选是查询中最为常用、最为重要的本领之一。它让我们能够从成千上万行数据中精准地捞取出符合特定条件的那些实现真正意义上的按需取数。这在数据库术语里叫做选择意思是从行的方向上对表进行选择筛选。五、让结果井然有序排序查询出来的结果有时候我们希望它按照某种顺序排列比如按成绩从高到低或者按年龄从小到大这样看起来更加清晰、更有条理。这就要用到排序对应的关键词是 ORDER BY意思是按照某列排序。比如我们想查出所有学生的信息并按年龄从小到大排列代码如下。SELECT*FROMStudentORDERBYSage;这条语句中ORDER BY Sage 表示按照年龄这一列排序。默认情况下是从小到大排列也就是升序。如果想从大到小排列也就是降序可以在后面加上一个表示降序的关键词代码如下。SELECT*FROMStudentORDERBYSageDESC;这里的 DESC 表示降序也就是从大到小。这条语句查出的学生将按年龄从大到小排列。排序让查询的结果井然有序便于我们观察和分析数据的分布规律是一个非常实用的功能。六、统计与汇总让数据开口说话查询不仅能取出原始数据还能对数据进行统计和汇总从而让数据开口说话告诉我们一些整体性的信息比如总数是多少、平均值是多少、最大值最小值是多少。这要用到一类特殊的函数叫做聚合函数。比如我们想知道学生表里一共有多少个学生代码如下。SELECTCOUNT(*)FROMStudent;这里的 COUNT 是一个聚合函数意思是计数COUNT 后面括号里的星号表示统计所有的行数。这条语句的意思是统计学生表里一共有多少行也就是有多少个学生返回一个总数。再比如我们想知道某门课程所有学生的平均成绩代码如下。SELECTAVG(Grade)FROMSCWHERECno0001;这里的 AVG 是聚合函数意思是求平均值。这条语句的意思是从选课表中先筛选出课程编号为某门课的所有记录然后求出这些记录中成绩的平均值。类似地还有求和的 SUM、求最大值的 MAX、求最小值的 MIN 等聚合函数它们都能对数据进行各种各样的汇总统计。更进一步我们还可以结合分组来进行统计。比如我们想知道每个院系各有多少个学生这就需要先按院系分组再对每组计数。分组对应的关键词是 GROUP BY意思是按照某列分组。代码如下。SELECTSdept,COUNT(*)FROMStudentGROUPBYSdept;这条语句中GROUP BY Sdept 表示按院系分组也就是把同一个院系的学生归到一组。然后 SELECT 中的 COUNT 对每一组分别计数。这条语句的意思就是把学生按院系分组统计出每个院系各有多少个学生。查询结果将是每个院系名称配上该院系的学生人数。这种分组统计的能力让我们能够从纷繁的数据中提炼出有价值的整体规律是数据分析中极为常用的利器。七、查询的高峰多表关联查询到目前为止我们的查询都只针对一张表。但是在现实中我们想要的信息常常分散在多张表里需要把它们关联起来一起查询这就是多表关联查询它是数据查询的高峰所在也是关系数据库威力的集中体现。我们来看一个例子。假设我们想查出每个学生选了哪些课程以及成绩是多少并且要显示学生的姓名和课程的名称。问题在于学生的姓名在学生表里课程的名称在课程表里而选课和成绩的信息在选课表里这些信息分散在三张表中必须把它们关联起来才能得到完整的结果。代码如下。SELECTStudent.Sname,Course.Cname,SC.GradeFROMStudent,Course,SCWHEREStudent.SnoSC.SnoANDCourse.CnoSC.Cno;这条语句稍显复杂让我们仔细解读。SELECT 后面我们要的是学生表的姓名、课程表的课程名、选课表的成绩由于这些列来自不同的表为了清楚起见我们在列名前面加上了表名加一个点作为前缀以表明这一列来自哪张表。FROM 后面列出了我们要用到的三张表学生表、课程表、选课表用逗号隔开。最关键的是 WHERE 部分的两个关联条件。第一个条件学生表的学号等于选课表的学号它把学生表和选课表关联了起来意思是只把学号相同的学生记录和选课记录配对在一起。第二个条件课程表的课程编号等于选课表的课程编号它把课程表和选课表关联了起来意思是只把课程编号相同的课程记录和选课记录配对在一起。通过这两个关联条件三张表就被正确地连接成了一个整体每一条选课记录都找到了它对应的学生姓名和课程名称。这条语句的整体效果就是查出一张综合的表每一行包含一个学生的姓名、他所选的一门课的名称、以及他这门课的成绩。原本分散在三张表里的信息通过关联查询被融会贯通地整合到了一起呈现出我们真正想要的完整结果。这种把多张表关联起来综合查询的能力正是关系数据库最为强大、最为精妙之处它让数据之间的种种联系得以充分地展现和利用。八、综合实战一条复杂查询的全貌最后让我们把前面学到的各种本领综合起来写一条相对复杂的查询体会一下它们协同作战的威力。假设我们想查出计算机系的学生中每个学生所选课程的平均成绩并且只显示平均成绩大于八十分的学生结果按平均成绩从高到低排列。这是一个综合性的需求让我们看看代码如何写。SELECTStudent.Sname,AVG(SC.Grade)ASAvgGradeFROMStudent,SCWHEREStudent.SnoSC.SnoANDStudent.Sdept计算机系GROUPBYStudent.Sno,Student.SnameHAVINGAVG(SC.Grade)80ORDERBYAvgGradeDESC;这条语句综合运用了多种本领我们简要解读。它关联了学生表和选课表并筛选出计算机系的学生这用到了多表关联和条件筛选。它按学生分组对每个学生求平均成绩这用到了分组和聚合函数。其中 AS AvgGrade 是给平均成绩这个结果起了一个别名方便引用和显示。HAVING 部分是对分组之后的结果再进行筛选只保留平均成绩大于八十分的组它和 WHERE 的区别在于WHERE 是分组前对行筛选HAVING 是分组后对组筛选。最后 ORDER BY AvgGrade DESC 把结果按平均成绩从高到低排序。这条语句虽然较长但它正是由我们前面学过的一个个本领有机组合而成的。它生动地展示了SELECT 语句是如何把挑选列、筛选行、多表关联、分组统计、结果筛选、排序等多种能力融为一炉去应对复杂的实际查询需求的。这正是SQL数据查询博大精深、变化无穷的魅力所在。九、结语行文至此我们通过一行行具体的代码由浅入深地走完了SQL数据查询的实战之旅。我们从查询语句的基本骨架出发认识了 SELECT 决定列、FROM 决定表、WHERE 决定行这一核心结构。我们从最简单的查看整张表开始依次学习了挑选需要的列、筛选满足条件的行、让结果排序、对数据进行统计汇总和分组又登上了多表关联查询这一高峰最后还综合运用各种本领写出了一条复杂的查询。一路走来我们真切地领略了 SELECT 语句那由简至繁、变化无穷的强大功能。回顾这场查询之旅我们能够深刻地体会到数据查询正是SQL的灵魂所在是关系数据库价值的最终归宿。我们存储数据的种种努力最终都是为了能够通过查询把数据中蕴含的信息和价值挖掘出来、利用起来。而SQL的查询恰恰把这件事做到了极致的优雅。我们只需用接近自然语言的语句清清楚楚地说明想要什么样的数据数据库便会在转瞬之间从浩如烟海的数据中把符合要求的结果精准地捞取出来奉送到我们面前。这种只需说要什么、无需管怎么做的查询体验正是SQL那非过程化特性最为淋漓尽致的体现。当我们今天能够熟练地写出从简单到复杂的各种查询语句能够在多张表之间自如地关联、在海量数据中精准地筛选、对纷繁的数据从容地统计分析时我们便真正掌握了在数据海洋中遨游捞珍的本领。希望大家不要止步于读懂这些代码更要亲自在真实的数据库中反复演练把这些查询语句一条条敲出来、跑起来亲眼见证数据在自己的指令下乖乖地呈现出我们想要的样子。唯有如此勤加历练这门在数据海洋中精准捞取所需的查询艺术才能真正成为我们得心应手的看家本领让我们在驾驭数据、挖掘价值的征途上走得更远、更加从容自信。