我们已经完成了四张表的创建,学会了创建表和查看表字段信息的语句。
接下来,我们来学点对数据的操作:增 删 查(一部分)改
先来看这四张表以及相关需求:
四张表
需求一:
这便是向我们创建好的空表里面,插入数据。具体语句我们使用INSERT INTO ,接下来介绍一番:
INSERT INTO:
先来申请英译中:
现在是逻辑课:按照语法来说"插入到"后面得加个地点吧,题上不是说了嘛,"添加到学生表"。根据前面的习惯,表名我们会select一个DATABASE。
(我们可以看到左侧,学生表stu是放在testdb中的)
所以按照猜测语句应该有这样一部分:
sql
INSERT INTO testdb.stu
后面按理说就应该是添数据对吧:但是一行数据我们要添加的数据项可能并不是全部字段(属性)------比如在stu表中,我们若添加数据只包含学号 、姓名 、学院编号。但是我们并不添加性别和出生日期这两个字段。
这种添加数据但是不包含所有字段的数据,需要我们自己指明要添加的字段名:
sql
#假如,指定添加该学生的学号,姓名和学院编号
INSERT INTO testdb.stu(stuid,stuname,deptid)
...
#字段之间用逗号隔开
如果你要添加的数据,包含全部的字段,这时候就不需要指明添加的字段名,默认你要添加所有字段。比如这里的需求:
但是,我们添加的核心,始终是数据。
我们会添加一个关键字VALUES:而数据就放在VALUES();的括号中。这里就应该这样表示:
sql
INSERT INTO testdb.stu
VALUES('2022121001','张三','男','2006-5-1','1');
#这是一行记录,一行记录的数据值之间也需要使用逗号隔开。其中字符型数据需要使用单引号。
发现没有,所有数据值的顺序对应我们字段的顺序。
补充:
我们前面在创建表的时候,不是有个字段NOT NULL约束吗?NOT NULL到底什么时候约束呢?就是添加记录的时候。
INTO子句中没有出现的字段,新添加的记录在这些字段上将被赋NULL值。但是表定义时有NOT NULL约束的字段不能取NULL值,添加记录时必须给其赋值。
我们运行一下:
sql
#Error Code: 1452.
/*Cannot add or update a child row:
a foreign key constraint fails (`testdb`.`stu`, CONSTRAINT `stu_ibfk_1` FOREIGN KEY (`deptid`) REFERENCES `dept` (`deptid`))*/
报错了,很好。具体错误是:无法添加或更新一个子行(row,在MySQL里,行也称作一条记录)。
外键约束无效:
原因是什么呢?是因为我们的外键约束失败了。外键为什么不行,还记得外键怎么来的吗?外键是另一张表的主键的引用,保证数据的完整性。不仅如此,从表中的外键列只能包含主表中已存在的主键值,避免了出现悬挂指针(指向不存在的数据)或数据不一致的情况。
外键能约束说明它心中已经有杆秤了,外键本质上是另一张表的主键。而有杆秤,说明该主表的主键列已经有值了------怎么至少也得有>=1个值吧,外键就依据这些现有的值来判断你添加的值是否有效了。------这就是外键约束。
解决方案:先在dept表里添加主键值,那就要我们再写一个INSERT INTO 呗,但是,你觉得这种写法可行吗?
sql
INSERT INTO testdb.dept(deptid)
VALUES('1');
看见没,前面的补充你只要明白了,这里你就知道为什么我们不能单单添加deptid了。NOT NULL约束对不对?
sql
INSERT INTO testdb.dept
VALUES('1','计算机学院');
运行一下,添加记录。
此时再添加这条学生信息,想必就不会外键失效了。
sql
INSERT INTO testdb.stu
VALUES('2022121001','张三','男','2006-5-1','1');
也成功了,但是文字的显示始终没有图形来得震撼。
我们前面说,DESC + 表名是查看表的字段信息,但是我们添加了数据,该怎么去看有数据的表呢?
SELECT * FROM
sql
SELECT * FROM 表名;
#表名包括了数据库
SELECT 表示筛选,*是通配符,表示"所有",FROM 表,连起来就是从某个表里的所有字段列中筛选数据------作用是:查询该表中的全部内容。
sql
SELECT * FROM testdb.dept;
#刚刚添加了一条数据,我们来显示一下
是吧,添加成功了。
这里浅浅说说,方便我们检验操作,因为我们后面不远处,还会说到select 。
需求一的参考代码:
sql
INSERT INTO testdb.dept
VALUES('1','计算机学院');
INSERT INTO testdb.stu
VALUES('2022121001','张三','男','2006-5-1','1');
需求二:
在学生表中删除学号为'2022121001'的学生信息。
分析需求:核心是删除一条记录,删的记录是哪里的? stu这张表里的。它直接报出了学号,咱们就得按照学号来检索删除。
按理说,这个"检索删除"有两步,但是学习的魅力就在于此:我们若只着眼于解决当下问题,就可以直接站在巨人的肩膀上,一步到位;但是我们若要追根溯源,探寻如何实现,也有前人给我们源码研究。
现在就允许我们先跪在巨人的肩膀上吧,学个DELETE from
DELETE FROM
DELETE FROM按照之前的设计后面也接个表名,你是这么猜,它也真的这么设计。这里就是:
sql
DELETE FROM testdb.stu
#我没打分号就表示这不是一句完整的语句,提醒一句
WHERE
WHERE关键字,WHERE
是 SQL 语言中的一个关键字,它用于指定 DELETE
、UPDATE
、SELECT
等语句中的条件,以限制哪些行(记录)会被影响或返回。
此处,DELETE FROM ... WHERE ...其结果是:指定删除。
怎么用呢? 比如:学生表中,你要指定删除一个叫"王五"的学生。用DELETE FROM ...WHERE就是:
sql
DELETE FROM testdb.stu WHERE stuname = '王五';
#指定删除学生表中学生姓名叫王五的学生的信息记录
运行当然运行不了,因为我们根本没添加过这条数据,我这里只是打个比方。
那实现这里的需求,也就照猫画虎了:
在学生表中删除学号为'2022121001'的学生信息。
sql
DELETE FROM testdb.stu WHERE stuid = '2022121001';
运行之前,先看一下表里的数据:
再运行一下我们的删除语句:
显示删除成功了。(有时发现不知不觉就熬了夜☕哈哈哈)
ok,我们通过select * 检查一下,是否真的删除了。
记录没了,确实删除了,直观吧
需求二的参考代码:
sql
DELETE FROM testdb.stu WHERE stuid = '2022121001';
需求三:
把课程表中课程编号为"CS003A"的课程的学分改为3。
分析:本质是什么,修改某条记录某个字段的值。关键词:修改表中的数据。
UPDATE ... SET ...
UPDATE 后面接表名,表示你要修改哪张表。SET 英译过来:"设置",这里和修改同义。
SET 设置的是前面确定表名的某个或多个字段 的值。
**扩展:**还记得前面说过的,WHERE加在不同的地方有指定的xx功能。和delete搭在一起,有指定删除的功能,那和set搭在一起,就有指定修改的功能。哟,这不巧了嘛。
我们的需求就是:指定修改课程表里课程编号为'CS003A'的课程记录的学分字段的值。(话有点长,但意思我写得清楚🤞)
比如:我们要把学生表里面的姓名叫"张三"的学生记录中的出生日期改成"2006-5-2"。
sql
UPDATE testdb.stu
SET birthday = '2006-5-2'
WHERE stuname = '张三';
#照样是举个例子
那么,这个需求,实现也近在眼前了:
把课程表中课程编号为"CS003A"的课程的学分改为3。
sql
UPDATE testdb.course
SET credit = 3
WHERE cid = 'CS003A';
#字符型数据才会加单引号,这里的学分不是字符型数据
但是,我们自己会发现这个修改数据是建立在有数据的基础上,若没有CSA003A这条课程的记录,甚至谈不上指定数据 。所以,我们还得手动添加一条数据记录。
sql
INSERT INTO testdb.course
VALUES('CS003A','数据库',2,'1');
#添加该课程编号整一条记录
那么我们先运行添加,查看:
再来修改学分为3:
好了,完成了需求三------修改数据。
需求三的参考代码:
sql
UPDATE testdb.course
SET credit = 3
WHERE cid = 'CS003A';
需求四:
查询学号为"2022121001"的学生所有信息。
分析:指定查询。
查询我们用关键字:SELECT,刚刚后面接*表示所有字段记录,若只有SELECT * FROM 表名,就表示查询该表中的全部内容。
现在我们要指定查询,就要在后面加个WHERE,起到我们期望的"指定"的效果。
WHERE 后面一般接字段名 = 某个值。
比如这里的:指定的是"学号为"2022121001"的学生"
sql
WHERE stuid = '2022121001'
我们要实现的是"查询...所有信息",前面再加上SELECT * FROM 表名
sql
SELECT * FROM testdb.stu
WHERE stuid = '2022121001';
我们运行一下,看看查询最后的效果是怎样。
所以得到需求四的实现代码:
sql
SELECT * FROM testdb.stu
WHERE stuid = '2022121001';
需求五:
查询学院名称为"计算机学院"的学生名单,显示学号、姓名、学院。
分析:也是指定查询,SELECT ... FROM...WHERE...是跑不了了。但是特殊的需求是,并非如上个需求显示所有字段的数据,而是只显示部分字段数据。别忘了,学生表中只有学院编号,要让我们显示的不是学院编号,而是学院表里面才有的学院名称。
这次查询,不是单纯的在一张表上查询,而是两张表。
首先改变的,只有 "*" 变成对应的字段名。
sql
#学号、姓名------ 这些字段来自stu表,后面FROM已经说明了是从学生表找。但是学院名称是在dept表中,则需要指明表
SELECT stuid,stuname,dept.deptname
FROM testdb.stu,testdb.dept
WHERE
我们的查询条件应该接在WHERE后,条件是deptname = '计算机学院',而这里值得注意的是,怎么样把两张表连起来。这两张表有主从关系,主从关系从何而来,学生表的外键是学院表主键的有效引用。
没错就是,主键外键 ------ 学生表的外键是学院表主键的有效引用。则同时满足stu.deptid = dept.deptid
sql
SELECT stuid,stuname,dept.deptname
FROM testdb.stu,testdb.dept
WHERE stu.deptid = dept.deptid AND deptname = '计算机学院';
AND
在SQL中用于表示关系的逻辑操作符和关键字,AND表示"前后两个表达式为真,记录就会被包含在查询结果中。",意思即"并且"。------ 呼应我们这里的学院名称为计算机学院 同时满足 两张表学员编号对应的要求。
运行效果:
查询学院名称为"计算机学院"的学生名单,显示学号、姓名、学院。
是不是挨个展示了 学号、姓名和学院名称。
这里,我们再介绍一种写法:
JOIN关键字
你需要通过两个表来进行联合查询(JOIN),join关键字后接上另一张表名。当将JOIN关键词放于FROM子句中,应有关键词ON与之对应,以表明连接的条件。
以前我们使用WHERE后面接查询条件和连接条件,现在我们使用ON。
查询学院名称为"计算机学院"的学生名单,显示学号、姓名、学院。
代码应该是这样:
sql
SELECT stuid,stuname,dept.deptname
FROM testdb.stu
JOIN testdb.dept
ON stu.deptid = dept.deptid AND deptname = '计算机学院';
#JOIN 后接另一张表,ON和JOIN连用,ON后接连接条件和查询条件
是不是一样的效果?
需求五的参考代码:
sql
#第一种:WHERE
SELECT stuid,stuname,dept.deptname
FROM testdb.stu,testdb.dept
WHERE stu.deptid = dept.deptid AND deptname = '计算机学院';
#第二种:JOIN ON
SELECT stuid,stuname,dept.deptname
FROM testdb.stu
JOIN testdb.dept
ON stu.deptid = dept.deptid AND deptname = '计算机学院';
#记得 SELECT ... FROM... 和 JOIN ... ON ...常见搭配
今天写得倒是很扎实,哈哈哈(意满离)