Chapter 3 —— SQL语言(2)

数据库系统原理   2023-10-10 13:49   51   0  

插入数据

· 我们使用INSERT语句来向数据库中添加新的数据:

INSERT INTO `表名` VALUES(常量1,常量2,...);

· 注意,插入的每一个值都要和字段顺序一一对应,并且每个值都要属于其字段所属的域

· 假设有下面这张student表:

24929_bba1_6750.png

· 执行下面的语句会报错,因为Sno的域是varchar,输入int型不满足域的要求

INSERT INTO `student` VALUES(126, "huangqirui", "Male", 21, "MA");

· 执行下面的语句会报错,因为输入了一个已经存在的元组,不满足关系中元组唯一性:

INSERT INTO `student` VALUES("121", "liyong", "Male", 20, "MA");

· 执行下面的语句会报错,因为字段的数量不相同,缺了一个:

INSERT INTO `student` VALUES("126", "huangqirui", "Male", 21);

· 当然,如果表设置了默认值,那可以用下面这种写法来指定填入的数据,其他没填的数据会自动使用默认值填充

INSERT INTO `student`(`Sno`, `Ssex`, `Sname`) VALUES("126", "Male", "huangqirui");

单表查询

简单查询

· 查询有很多种,我们先从最简单的单表查询入手。所谓单表查询,顾名思义,就是只在一张表内进行查询。

· 我们来看看最基础的查询语句长什么样:

SELECT 列名1 [[列名2], [列名3], ...] FROM 表名 [WHERE 检索条件];

· 看上去有点抽象,我们一个个看。

· 首先,查询的关键字是SELECT;然后后面要跟上你想看到的列的数据,你想看到哪些列就跟上哪些列的列名;然后FROM后跟上要从哪张表里面查;然后WHERE是筛选条件,后面会讲。

· 每个英文单词后面跟着的叫做子句,如SELECT子句,FROM子句,WHERE子句。

· 注意,查询的关键字顺序很严格,请严格按照上面的顺序来书写

· 这个语句的作用其实就是从表中依次取出一个个元组,然后检查是否满足检索条件,如果满足则将元组(或分量组)放入结果表。

· 我们来看一些例子,首先我们有一张student表:

27342_nuyo_3243.png

· 下面的语句会把整张表筛选出来,*代表的就是所有列

SELECT * FROM student;

· 下面的语句用于查询所有学生的学号和姓名,类似于27432_lswg_6086.png

SELECT `Sno`,`Sname` FROM student;

· 下面的语句会筛选出性别这一列:

SELECT `Ssex` FROM student;

但是结果是这样的:

27523_kzfu_7949.png

· 这看上去有点奇怪,因为我们只想知道有多少性别有多少类,不需要重复的查看性别,因此我们可以用DISTINCT来实现去重

SELECT DISTINCT `Ssex` FROM student;

这看上去就合理多了:

27596_r4ho_7562.png

· 接下来我们玩点花的。

· 首先,我们可以对查询后的值做运算,当然,只有数值型才能做运算:

SELECT 2023-`Sage` FROM student;

28705_8jyz_7093.png

· 然后我们可以使用AS关键字来给查询的结果起个别名

SELECT 2023-`Sage` AS `born_year` FROM student;

28800_nrtc_4675.png

· 还可以给筛选出来的每一列都改名:

SELECT `Sname` AS `Name`,
        2023-`Sage` AS `BirthYear`
        FROM student;

29924_nlzi_1654.png

条件筛选

· 接下来我们要使用WHERE关键字来做条件筛选了。

· 下面列举了能跟在WHERE后面的谓词:

30199_7zxx_3106.png

· 我们继续用这张学生表来做例子:

30654_tfrt_3098.png

· 下面的代码可以筛选出表内所有CS系的学生的名字:

SELECT `Sname` FROM student WHERE `Sdept`=`CS`;

· 下面的代码可以筛选出表内所有年龄大于18岁的学生的名字:

SELECT `Sname` FROM student WHERE `Sage`>18;

· 下面的代码可以筛选出表内所有不是CS系的学生的名字:

SELECT `Sname` FROM student WHERE `Sdept`!=`CS`;
SELECT `Sname` FROM student WHERE `Sdept`<>`CS`; // <>也是不等于哦~

· BETWEEN....AND....的使用:找到年龄在18到20岁之间的学生的姓名:

SELECT `Sname` FROM student WHERE `Sage` BETWEEN 18 AND 20;

· NOT的使用:找到年龄不在18到20岁之间的学生的姓名:

SELECT `Sname` FROM student WHERE `Sage` NOT BETWEEN 18 AND 20;

· IN的使用:找到CS系和IS系的学生姓名:

SELECT `Sname` FROM student WHERE `Sdept` IN (`CS`, `IS`);

· 找到既不是18岁也不是20岁的学生的姓名:

SELECT `Sname` FROM student WHERE `Sage` NOT IN (18, 20);

· 接下来介绍比较重要的字符匹配,它是一种模糊查询,需要使用LIKE关键字

· 首先介绍百分号(%),它代表任意长度的字符串,如a%b就是要匹配以a开头,b结尾的任意字符串。

· 然后是下划线(_),它代表任意的单个字符,如a_就是要匹配以a开头,长度为2的字符串,如ab,ac。

· 然后是转义符(\),它用于加在特殊符号前,如百分号和下划线,这样SQL就会把它当普通字符看待,如\%就是字符%,\_就是字符_。

· 接下来举一些例子。

· 查询所有姓张的同学的学号:

SELECT `Sno` FROM student WHERE `Sname` LIKE "张%";

· 查询不姓张的同学的学号:

SELECT `Sno` FROM student WHERE `Sname` NOT LIKE "张%";

· 查询所有”张某某“的同学的学号:

SELECT `Sno` FROM student WHERE `Sname` LIKE "张__";

· 查询第二个字是”阳“的同学的学号:

SELECT `Sno` FROM student WHERE `Sname` LIKE "_阳%";

· 查询名字带下划线的同学的学号:

SELECT `Sno` FROM student WHERE `Sname` LIKE "%\_%";

· 涉及空值的情况:假设有一个SC表,某些学生选修课程后没参加考试,所以有选课记录但没有成绩,查询缺少成绩的学生的学号以及相应的课程号:

SELECT `Sno`, `Cno` FROM `SC` WHERE `Grade` IS NULL;

多条件运算

· 还是以这个学生表为例:

33303_ba25_7393.png

· 选出CS系的男生:

SELECT * FROM student WHERE `Ssex`="Male" AND `Sdept`="CS";

· 选出所有男学生,不要CS系的:

SELECT * FROM student WHERE `Ssex`="Male" AND `Sdept`!="CS";

· 选出”CS系的女学生”以外的学生:

SELECT * FROM student WHERE !(`Ssex`="Female" AND `Sdept`="CS");

· 接下来用这张表来做点练习:

33693_14gx_8861.png

· 选出不大于19岁的男学生:

SELECT * FROM student WHERE `Ssex`="Male" AND `Sage`<=19;

· 选出CS系以外的男学生:

SELECT * FROM student WHERE `Ssex`="Male" AND `Sdept`!="CS";

· 查询不姓张的女学生的学号,姓名和院系:

SELECT `Sno`, `Sname`, `Sdept` FROM student WHERE `Sname` NOT LIKT "张%" AND `Ssex`="Female";

· 选出CS系、IS系里名字带下划线的学生:

SELECT * FROM student WHERE `Sname` LIKE "%\_%" AND `Sdept` IN ("CS", "IS");

· 一个小测试题:查询下列customer表中没有被id=2的客户推荐的客户的姓名。

45764_6jbo_1366.png

--注意是null的情况!!!
SELECT `name` FROM customer WHERE `Rederee_id`!=1 AND `Referee_id` IS NULL;

· 多条件运算:注意AND的优先级比OR高!如筛选出下列表中所有工资少于1500元或大于2000元并且是03系的教师姓名:

46475_tnc8_3414.png

--注意OR语句要加上括号,否则会先运算后面的AND!!
SELECT `Tname` FROM Teacher WHERE (`Salary` < 1500 OR `Salary` > 2000) AND `D#`="03";

排序语句

· 我们使用ORDER BY子句来对筛选出来的结果进行排序,它可以按一个或多个属性列进行排序。

· 如果要升序则使用ASC降序则使用DESC。默认是升序。

· 比如查询全体学生,按年龄升序排序:

SELECT * FROM students ORDER BY `Sage` ASC;

· 查询全体女同学,院系按首字母升序,同院系按年龄降序:

SELECT * FROM students
WHERE `Ssex`="Female"
ORDER BY `Sdept`, `Sage` DESC;

· 限制结果个数:使用LIMIT关键字可以限制最后结果的数量,常与ORDER BY连用:

SELECT * FROM students
ORDER BY `Sage`
LIMIT 3; --限制最多3条结果

统计函数

· 使用统计函数可以帮助我们对数值进行统计,常用的统计函数如下:

5528_zvda_5856.png

· 我们用下面这张Student表来演示一下统计函数:

5608_ybtv_8010.png

· 计算学生总人数:

SELECT COUNT(*) FROM `Student`;

· 计算这些学生来自多少个学院:

SELECT COUNT(DISTINCT `Sdept`) FROM `Student`;

· 找出姓张的同学的数量:

SELECT COUNT(*) FROM `Student` WHERE `Sname` LIKE "张%";
SELECT COUNT(`Sname` LIKE "张%") FROM `Student`;

· 值得注意的是,聚集函数不能直接嵌套使用,如下面的句子是错误的:

SELECT MAX(COUNT(*)) FROM ...

分组语句

· 我们会使用GROUP BY字句对筛选后的结果进行分组,它可细化聚集函数的作用对象。

· 如果未对查询结果分组,聚集函数就会作用于整个查询结果;分组之后,聚集函数就会分别作用于每个组。

· 该语句会按指定的一列或多列值分组,值相等的为一组。

· 接下来我们以这个学生表来做例子:

18990_y0vx_3251.png

· 求每个系的平均年龄:

SELECT `Sdept`, AVG(`Sage`) 
FROM student
GROUP BY `Sdept`;

19168_xqff_4677.png

· 求每个系男生女生的平均年龄:

SELECT `Ssex`, `Sdept`, AVG(`Sage`)
FROM student
GROUP BY `Ssex`, `Sdept`;

19409_rzcb_2747.png

· 如果要对分组之后的结果再进行筛选,我们就不使用WHERE子句了,而是HAVING子句。

· 找出平均年龄小于20岁的系:

SELECT `Sdept`, AVG(`Sage`)
FROM student
GROUP BY `Sdept`
HAVING AVG(`Sage`) < 20;

19438_mzzt_5686.png

· 找出平均年龄小于20岁的系的人数:

SELECT `Sdept`, COUNT(*)
FROM student
GROUP BY `Sdept`
HAVING AVG(`Sage`) < 20;

19578_7y88_2242.png

· 可以发现,HAVING子句是作用于组的,并从中选出满足条件的组,因此HAVING子句一定要跟在GROUP BY后面;而WHERE子句是作用于基表或视图的,并从中选出满足条件的元祖

· 当然,HAVING是可以和WHERE连用的,用下面这个SC表举例:

19749_yvi5_2024.png

· 找出不及格课程大于等于2门的同学(60分或以上及格):

SELECT `S#`
FROM SC
WHERE `Score` < 60
GROUP BY `S#`
HAVING COUNT(*) >= 2;

· 找出不及格人数大于等于10人的课程号:

SELECT `C#`
FROM SC
WHERE `Score` < 60
GROUP BY `C#`
HAVING COUNT(*) >= 10;

· 接下来用这张Student表做习题:

20110_5tik_3013.png

· 查询姓张的学生的系的数量

SELECT COUNT(DISTINCT `Sdept`)
FROM Student
WHERE `Sname` LIKE "张%";
-- 注意以下写法是错误的,不可以用GROUP BY来代替DISTINCT,下面运行的结果是两行1,因为分出了2个组
/*
SELECT COUNT(*)
FROM student
WHERE `Sname` LIKE "张%"
GROUP BY `Sdept`;
*/

· 查询每个系年龄最小的女生多少岁?请按Sdept - MAXage的格式输出:

SELECT `Sdept`, MIN(`Sage`)
FROM student
GROUP BY `Sdept`, `Ssex`
HAVING `Ssex` = "Female";

· 找出女生人数大于等于2个的系:

SELECT `Sdept`
FROM student
GROUP BY `Sdept`, `Ssex`
HAVING COUNT(*) >= 2 AND `Ssex`="Female";
博客评论
还没有人评论,赶紧抢个沙发~
发表评论
说明:请文明发言,共建和谐网络,您的个人信息不会被公开显示。