SQL是数据库的查询语言,今天我们来学习一下。文章的语句都是在Navicat premium的query界面运行的,使用的数据库是mysql,具体的软件安装使用可自行百度。
为了有数据演示,我这里创建了一个school的数据库,里面包括四张表,详细内容如下截图,我是先在Excel里面创建了数据,然后导入数据库的,如果想要数据可在后台回复“SQL”。
一、检索语句
select column from table
table是表名,上图中的course、sc、student、teacher;column是我们要查询的字段/列,如果用通配符*代替就是获取所有的字段。
这里只显示运行了 select * from sc这条语句。
其实在运行select cid from sc这条语句的时候会发现结果是返回了所有的cid,但这些cid有许多重复的,如果想要获得唯一的cid只需要distinct关键词就可以了。
二、过滤数据
WHERE子句
1、单条件筛选
学号为1000的同学的所有成绩
2、多条件筛选
学号1000和课程编号8的课程成绩
3、AND、OR、()三者运算级
学号为1000同学的编号8或者编号31两门课的成绩
因为成绩表里面课程编号最高是到30的,所以学生1000是没有学cid=31的这门课的,只得到一条结果,这里的()的运算优先级是高于and高于or的,如果没有括号的话,就先执行and,返回结果为空,最终返回cid=8所有学生的成绩了。
4、IN操作符
学号为1000同学的课程编号3或6或9或14或31的成绩
如果用or语句的话整条查询语句就会非常长,但是用IN就会简洁很多。IN操作符是用来指定条件范围,范围中的每个条件都可以进行匹配,IN的执行要比or更快,而且IN是可以包含select子句的,使得可以动态的建立WHERE子句。
5、NOT操作符——否定它之后所跟的任何条件
cid一共是30个,排除了括号里面的四个剩下26个。
6、操作符:=、<>、!=、<、 <= 、> 、>= 、between
7、通配符过滤
LIKE操作符
百分号(%)通配符:表示任何字符出现任意次数
下划线(_)通配符:只匹配单个字符
对比两个结果可以发现%返回了'zhang'之后两个字母和三个字母的姓名结果
'__'这里是用了两个'_',因为一个的结果为空,两个就只返回了'zhang'之后两个字母的结果。
通配符虽然比较有用,但是他的搜索速度要比其他搜索要慢,而且除非绝对有必要,否则不要把通配符放在搜索模式的开始处,因为这样搜索起来是最慢的。
三、排序数据
1、ORDER BY
得到数据并按score排序,默认的是升序,如果要降序加一个DESC关键字就可以了。
如果是对多个列排序只需要把相应的列放在order by后面就可以了,而DESC关键字只应用到直接位于其前面的列名。
如图先按score排序,但是由于desc只作用在cid上面,所以score是默认的升序,而cid则是在score相同的情况是降序排序。
2、LIMIT
可以对比上一张发现我们的结果是这个学生成绩排名第三到第七的结果,limit的第一个参数表示从第几个位置开始,计数是从0开始,所以2得到的结果是从第三行开始,如果省略表示从0开始,第二个参数表示返回记录行的最大数,这里写的是5,如果结果只有3行就只返回3行。
同时在mysql里面是使用limit,但是在SqlServer里是用top,Oracle则是用rownum。
四、汇总分组数据
聚合函数有五个,分别是count、sum、avg、max、min,作用分别是计数、求和、求平均、最大值、最小值。
分组是group by函数,得到的结果类似Excel的数据透视表。
接下来说一下聚合函数和分组需要注意的地方。
1、count有两种用法
count(*)对表中行的数据进行计算,即使表中包含空值也会被计数。
count(column)对特定列中有值得行进行计数,忽略NULL值。
2、group by子句可以包含任意数目的列,这使得能对分组嵌套。
3、group by子句中的列必须是检索列或者有效的表达式,不能是聚合函数。
4、除聚合函数外,select语句中的每个列都必须在group by子句中给出。
5、having支持所有where操作符,差别是where过滤行,having过滤分组。
五、条件判断
1、IF
SQL中的IF使用和Excel里面的差不多,可以用于条件判断,也可以用于存储过程的流程控制。
2、CASE WHEN
图中两段SQL语句得到的结果和上面IF得到的结果是一样的,但是两个case语句里面ssex的位置有区别,第一种就是简单的case函数写法,第二种是case搜索函数写法。
我们还可以用select和case完成二维表的输出形式,实现数据透视表的功能。
六、子查询和联结表
之前的操作都是基于一张表的,但是实际工作中会有很多张表,而且你需要的数据不会全部都在一张表里面,这时候就需要操作多张表来获取数据了。
比如想查询没有学过某位老师的学生学号和姓名,这时就需要在多张表里面去获取数据。
这里我们可以先建一个查询获得学过这个老师课程的学生的学号的子查询,然后在这个的基础上再去获取没有学过这位老师课程的学生学号和姓名。
再比如要获取学生的学号、姓名、选课数、总成绩,这时也是需要多张表操作的。
这时有两种处理方式,一种是联结表的方式,我们可以把需要的表通过限定的列名来关联,比如这里的student.sid和sc.sid,另一种是利用join合并表的方式,把需要的数据从多张表合并到一张表,然后再进行相关的操作。
这里的join有right、left、inner、outer几种用法,类似于数学的交集和并集运算,这里找了一张图供参考:
然后就是为什么我们这里写的left join,实际上这里不管是left还是right或者inner结果都一样,因为我们的student.sid和sc.sid是一样的,但是选择left是因为student的sid肯定是完整的,有学生可能没选课,那他在sc表中是没有数据的,用left之后如果为空是同样会返回的,从而不会漏掉。
七、视图
视图是虚拟的表,与包含数据的表不一样,视图只包含使用时动态检索数据的查询。
如果查询一位老师教的课程里学生的学号、姓名、课程名称、学生成绩,可以通过表联结来查询。
但是如果这项操作需要经常使用,比如要经常查不同老师带的学生成绩情况,不停的写SQL就比较麻烦,这时就可以用视图了,把学生学号、姓名、课程名称、成绩、老师名字放在视图里,这样下次查询的时候只需要简单SELECT语句就可以获取到数据了。
当你创建好视图的时候在左边的VIEWS下面是有你创建的视图,当然如果不用了也可以删除的。
视图重用SQL语句,同时简化复杂的SQL操作,使用的时候只是使用表的组成部分而不是整张表,可以给用户授予表的特定部分的访问权限而不是整个表的访问权限,从而能保护数据。创建好视图之后可以进行SELECT操作,过滤和排序数据,将视图联结到其他的视图或表。
八、存储过程
之前的需求都可以用一条SQL语句来完成,但实际上有许多需求一条SQL语句是无法完成的,这时就需要存储过程,存储过程简单来说,就是为完成某个特定功能的SQL语句集,经编译后存储在数据库中,用户通过指定存储过程的名字并给定参数来调用执行它。
存储过程把处理封装在一个单元中,简化复杂的操作,同时保证了数据的完整性并防止出错,而且要比使用单独的SQL语句要快。以上就是存储过程的简单、安全、高性能的好处,但存储过程的编写要比SQL语句复杂,就需要更高的技能和更丰富的经验了。
1、创建不带参数的存储过程
以上是创建存储过程的两种方式,一种是通过CREATE PROCEDURE语句创建,这里创建了一个名为stu_avg_score的存储过程,虽然这里没有参数,但是后面的()是必须要有的,通过CALL调用就可以得到结果了,本例中的为 CALL stu_avg_score()。另外一种方式是通过新建函数功能来创建,不过这里Type类型要选择PROCEDURE而不是FUCTION,然后按照流程把对应的内容填上就可以了,点击Execute在Result里面查看结果,也可以用CALL调用。这里BEGIN和END语句用来限定存储过程体,过程体本身仅是一条简单的SQL语句。
2、创建带参数的存储过程
三种参数:
IN:输入参数,表示调用者向过程传入值(传入值可以是字面量或变量)
OUT:输出参数,表示过程向调用者传出值(可以返回多个值)(传出值只能是变量)
INOUT:输入输出参数,既表示调用者向过程传入值,又表示过程向调用者传出值(值只能是变量)
这里s1是需要输入的参数,是学生的学号,然后返回的ccount得到的是学生的选课数,在CALL调用的时候变量ccount要加@,调用时是不显示数据的,所以可以用select选择显示。
也可以用函数生成的形式来,只需要在对应的地方填上语句或者参数就可以了,可以直接执行,也可以用CALL调用生成结果。
这里只是展示了存储过程的创建和使用以及一些注意事项,它的实际功能比这些要复杂和强大的多,还需要实战中去体会和学习。