本文将讲述select语句的详细用法,select用于对数据查询,我们对一个数据库的操作大部分时候都是对数据进行查询,我们将通过使用select语句来满足各种各样的查询需求。实验环境我们使用SQLiteStudio:
为了研究方便,我们将使用以下预备数据环境:(一共三张表)
Cpno是先修课程名称,也就是我们在修这门课之前需要先修某门课的名称。
假如现在我们只在一个数据表里面查询。
例:查询全体学生的学号和姓名
select Sno,Sname from Student
关系代数式子:
∏ S n a o , S n a m e ( S t u d e n t ) \prod_{Snao,Sname}(Student) ∏Snao,Sname(Student)
假如我们需要获取整个表的记录:
select * from Student
例:我们需要获取全体学生的姓名和出生年份
select Sname, 2020-Sage from Student;
但这样是不好的,因为把常数写入了代码里面,我们在代码里面需要规避常数的出现。
这时候我们需要到系统函数来计算当前的年份
select sname ,year(getdate())-sage as birthday from student;
附:as 是显示的列别名,只对查询结果和过程有效,对原表不产生影响。
假如我们要小写字母标识的话,需要到系统函数:lower(
select lower(sdept) from student;
选择行一个最大问题就是重复项的出现,我们需要到 关键字 “distinct” 来消除
假如我们需要到查询选修了课程的学生的学号
假如我们使用
select sno from sc
会有重复的,因为一个学生会选择多门课
我们只需要使用:
select distinct sno from sc
即可对【结果】行出现重复的元组进行去重。
注意是对结果进行去重,对原表没有影响。
distinct 是对整个元组的重复起作用的,不是对某个属性的去重。
我们更多情况是进行条件查询,这时候需要到 where 关键字了。
条件查询包括:【大小】,【范围】,【集合】,【字符串匹配】,【空值查询】,【多重条件】的知识
最简单就是大小,运算符如下:
= , > , < , < = , > = , ! = , < > , ! > , ! < =,>,<,<=,>=,!=,<>,!>,!< =,>,<,<=,>=,!=,<>,!>,!<
<>是不等于的意思和!=是一样的
查询计算机系全体学生的名单:
select Sname from student where Sdept='CS'
查询所有成绩不及格的学生学号:
select distinct sno from sc where grade<60
虽然我们使用大小也能确定范围,但是关于范围我们由更专业的一套表达:between and 和 not betweeen and。
查询年龄在20-23岁的学生的姓名,性别,年龄:
select sname, ssex, sage from student where sage between 20 and 23
在等值查询(某个属性等于某个数值)的时候,我们只能给出一个等值条件,假如我们有多个呢?我们就需要到集合 in(v1,v2…) 函数来表达。
例如我们需要查询在信息系(IS),数学系(MA),计算机科学系(CS)的学生的姓名和性别。
select sname,ssex from student where sdept in('IS','MA','CS');
那假如我们需要查询不是某些值的话:not in 即可
select sname,ssex from student where sdept not in('IS','MA','CS');
我们需要到正则表达式来进行匹配,需要到关键字 like
在sql里面使用到的正则表达语法我们只需要掌握两个:%和_,%标识不定长字符串,_标识单个字符。
假如我们需要查找所有姓“刘”的学生的姓名,学号和性别:
select sname,sno,ssex from student where sname like "刘%";
假如否定:
select sname sno,ssex from student where sname not like "刘%";
假如我们需要使用到%和_作为正常的字符:
使用escape关键字
select Cno from Course where like 'DB\_Design' escape '\'
在一个数据表中我不可避免会存在空值,这个时候就需要我们使用 is null 和 is not null 来查询了,注意的是空值不能使用=那些符号计算。
例如我们需要查询某些学生缺少成绩的对应的课程号
select sno,cno from sc where grade is null;
对于多重条件,我们使用 and 和 or 来满足
我们将使用order by 关键字
对全体学生的年龄进行排序降序:
select sno from student order by ssage desc
对系号进行升序排序, 对年龄降序排序:
select * from student order by sdept,sage desc
需要注意的是count函数不统计空值。
统计学生的总人数:
select count(*) from student
select avg(grade) from sc where cno=1
这个用于细化集函数的作用对象,因为我们直接使用集函数是对所有的查询结果进行操作的,那现在假如我们对不同的查询分组,那就需要到 group by 关键字了。
求每个课程号的选择的人数:
select cno,count(sno) from sc group by cno
查询每个课程90分以上的人数:
select cno,count(sno) where grade>90 group by cno;
这个先把所有的大于90分的人找出来,再进行分组,sql是按照语法的顺序执行操作的。
也就是我们对查询结果不满足,还需要对查询之后的结果再进行一次查询,需要到having关键字。
例如查询选修了3门课程以上的学生学号
select sno from sc group by sno having count(*)>=3
我们首先把选课记录以学号为相同元素归并起来,再对每个组筛选出总数大于3的sno
select sno from sc group by sno
执行之后:
sno |
---|
01 |
01 |
02 |
02 |
02 |
03 |
然后我们对每个group 进行having 操作 集函数
例如:
统计每门课的最高分:
select cno,grade from sc group by cno having max(grade)
执行逻辑:
先根据cno分组把相同的cno的元组筛选出来,然后对于每一个组的grade进行统计最高分
以上我们只是涉及了单表查询,也就是我们只是在一个表里面寻找答案,但是往往答案会在多个表出现,我们需要把结果整合起来。
不同的表的列名字,我们需要使用表的前缀进行定义:
Student.sno 和 SC.sno 是不同的
把查询结果连接在一起,这个时候就涉及到连接查询了
假如我们执行:
select Student.*,SC.* from student,SC
得到:
这样子是没有意义的,因为里面出现了重复的列,而且元组的数据没有一致的意义。这个只是最普通的笛卡尔积。我们需要真正有意义的是:等值连接
实例:查询每个学生的所有信息和他所选修课程的情况
select Student.*,SC.* from Student,SC where Student.sno=SC.sno
我们需要使用=来划出一个桥,说白了就是构建两个表之间的关系。
实例:查询计算机系(CS)的学生的学号,姓名,所在系,选修的课程号,成绩
select Student.sno,Student.sname,Student.sdpet,SC.cno,SC.grade from Student,SC where Student.sno=SC.sno and Sdept='CS'
假如某些时候我们需要到一个表的两次使用(比如使用同一个表连接起来),我们需要对表进行起别名再连接。
这种情况出现在一个表的某个列的信息依赖于该表其他列信息的情况。
比如:查询每门课程的先修课程的课程号
select a1.cno,a2.cno from Course a1, Course a2 where a1.cpno=a2.cno
select a.sno from SC a, SC b where a.sno=b.sno and a.cno!=b.cno and a.cno=2 and b.cno=3