十三、表数据的增、删、改操作
本文介绍了在 MySQL 中添加、修改和删除表数据的具体方法,也就是对表数据的增、删和改操作。这3种操作在实际开发中经常应用。因此,读者需要认真学习本文的内容,争取做到举一反三、灵活应用。
文章目录
前置知识:
一、数据库开发与实战专栏导学及数据库基础概念入门
二、MySQL 介绍及 MySQL 安装与配置
三、MySQL 数据库的基本操作
四、MySQL 存储引擎及数据类型
五、数据导入与基本的 SELECT 语句
六、MySQL 数据库练习题1(包含前5章练习题目及答案)
七、MySQL 多表查询详解(附练习题及答案----超详细)
八、MySQL 常用函数汇总(1)
九、MySQL 常用函数汇总(2)
十、MySQL 聚合函数、分组查询及过滤分组
十一、子查询详解
十二、创建和管理表
成功创建数据库和数据表以后,就可以针对表中的数据进行各种交互操作了。这些操作可以有效地使用、维护和管理数据库中的表数据,其中最常用的就是添加、修改和删除操作。本文将详细介绍如何通过 SQL 语句来实现表数据的增、删和改操作。本文知识架构及重难点如下:
一、插入数据
实际问题:
解决方式:使用 INSERT
语句向表中插入数据。 在建立一个空的数据库和数据表时,首先需要考虑如何向数据表中添加数据,该操作可以使用 INSERT
语句来完成。使用 INSERT
语句可以向一个已有数据表中插入一个新行,也就是插入一行新记录。在 MySQL
中,INSERT
语句有 3种 语法格式,分别是 INSERT…VALUES
、INSERT…SET
和 INSERT…SELECT
语句。下面将分别进行介绍。
1.1 使用 INSERT…VALUES 语句插入数据
使用 INSERT…VALUES
语句插入数据,是 INSERT
语句最常用的语法格式,如下所示:
INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
[INTO] 数据表名 [(字段名,…)]
VALUES ({值 | DEFAULT},…),(…),…
[ ON DUPLICATE KEY UPDATE 字段名=表达式,…]
参数说明如下:
[LOW_PRIORITY|DELAYED|HIGH_PRIORITY]
:可选项,其中,LOW_PRIORITY
是INSERT
、UPDATE
和DELETE
语句都支持的一种可选修饰符,通常应用在多用户访问数据库的情况下,用于指示MySQL
降低INSERT
、DELETE
或UPDATE
操作执行的优先级;DELAYED
是INSERT
语句支持的一种可选修饰符,用于指定MySQL
服务器把待插入的行数据放到一个缓冲器中,直到待插数据的表空闲时,才真正在表中插入数据行;HIGH_PRIORITY
是INSERT
和SELECT
语句支持的一种可选修饰符,用于指定INSERT
和SELECT
操作优先执行。[IGNORE]
:可选项,表示在执行INSERT
语句时,所出现的错误都会被当作警告处理。[INTO]
数据表名:可选项,用于指定被操作的数据表。[(字段名,…)]
:可选项,当不指定该选项时,表示要向表中所有列插入数据,否则表示向数据表的指定列插入数据。VALUES ({值|DEFAULT},…),(…),…
:必选项,用于指定需要插入的数据清单,其顺序必须与字段的顺序相对应。其中,每一列的数据可以是一个常量、变量、表达式或者NULL
,但是其数据类型要与对应的字段类型相匹配;也可以直接使用DEFAULT
关键字,表示为该列插入默认值,但是使用的前提是已经明确指定了默认值,否则会出错。ON DUPLICATE KEY UPDATE
子句:可选项,用于指定向表中插入行时,如果导致UNIQUE KEY
或PRIMARY KEY
出现重复值,系统会根据UPDATE
后的语句修改表中原有行数据。
INSERT…VALUES
语句在使用时,通常有以下3种方式:
情况1:为表的所有字段按默认顺序插入数据。语法如下:
#值列表中需要为表的每一个字段指定值,并且值的顺序必须和数据表中字段定义时的顺序相同
INSERT INTO 表名 VALUES (value1,value2,...);
示例1:通过INSERT…VALUES语句向数据表tb_admin中插入一条完整的数据。
mysql> SELECT * FROM tb_admin;
Empty set (0.00 sec)
mysql> DESC tb_admin;
+------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+-------+
| id | int | NO | PRI | NULL | |
| username | varchar(40) | YES | | NULL | |
| password | varchar(30) | NO | | NULL | |
| createtime | datetime | YES | | NULL | |
+------------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
mysql> INSERT INTO tb_admin VALUES(1,'amo','123456','2023-01-31 03:32:50');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT * FROM tb_admin;
+----+----------+----------+---------------------+
| id | username | password | createtime |
+----+----------+----------+---------------------+
| 1 | amo | 123456 | 2023-01-31 03:32:50 |
+----+----------+----------+---------------------+
1 row in set (0.00 sec)
情况2:为表的指定字段插入数据,就是在INSERT语句中只向部分字段中插入值,而其他字段的值为表定义时的默认值。语法如下:
INSERT INTO 表名(column1 [, column2, …, columnn]) VALUES (value1 [,value2, …, valuen]);
#在 INSERT 子句中随意列出列名,但是一旦列出,VALUES中要插入的value1, valuen需要与
#column1,columnn列一一对应。如果类型不同,将无法插入,并且MySQL会产生错误
示例2:通过INSERT…VALUES语句向数据表tb_admin中插入数据记录的一部分。
mysql> INSERT INTO tb_admin(id,username,password) VALUES (2, 'Jerry', 'Jerry123456');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT * FROM tb_admin;
+----+----------+-------------+---------------------+
| id | username | password | createtime |
+----+----------+-------------+---------------------+
| 1 | amo | 123456 | 2023-01-31 03:32:50 |
| 2 | Jerry | Jerry123456 | NULL |
+----+----------+-------------+---------------------+
2 rows in set (0.00 sec)
情况3:同时插入多条记录。INSERT语句可以同时向数据表中插入多条记录,插入时指定多个值列表,每个值列表之间用逗号分隔开,基本语法格式如下:
INSERT INTO table_name VALUES
(value1 [,value2, …, valuen]), (value1 [,value2, …, valuen]),
……
(value1 [,value2, …, valuen]);
#或者
INSERT INTO table_name(column1 [, column2, …, columnn]) VALUES
(value1 [,value2, …, valuen]), (value1 [,value2, …, valuen]),
……
(value1 [,value2, …, valuen]);
示例3:通过INSERT…VALUES语句向数据表tb_admin中一次插入多条记录。
mysql> INSERT INTO tb_admin(id,username,`password`,createtime) VALUES
-> (3, 'Paul', 'Paul123456', NOW()),
-> (4, 'Ben', 'Ben123456', NULL),
-> (5, 'Crystal', 'Crystal123456', NOW()),
-> (6, 'Jason', 'Jason123456', NULL);
Query OK, 4 rows affected (0.00 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM tb_admin;
+----+----------+---------------+---------------------+
| id | username | password | createtime |
+----+----------+---------------+---------------------+
| 1 | amo | 123456 | 2023-01-31 03:32:50 |
| 2 | Jerry | Jerry123456 | NULL |
| 3 | Paul | Paul123456 | 2023-01-31 03:44:37 |
| 4 | Ben | Ben123456 | NULL |
| 5 | Crystal | Crystal123456 | 2023-01-31 03:44:37 |
| 6 | Jason | Jason123456 | NULL |
+----+----------+---------------+---------------------+
6 rows in set (0.00 sec)
使用 INSERT
同时插入多条记录时,MySQL
会返回一些在执行单行插入时没有的额外信息,这些信息的含义如下:
Records: 表明插入的记录条数
Duplicates: 表明插入时被忽略的记录,原因可能是这些记录包含了重复的主键值
Warnings: 表明有问题的数据值,例如发生数据类型转换
一个同时插入多行记录的 INSERT
语句等同于多个单行插入的 INSERT
语句,但是多行的 INSERT
语句在处理过程中 效率更高 。因为 MySQL
执行单条 INSERT
语句插入多行数据比使用多条 INSERT
语句快,所以在插入多条记录时最好选择使用单条 INSERT
语句的方式插入。VALUES
也可以写成 VALUE
,但是 VALUES
是标准写法。
#注意: 字符和日期型数据应包含在单引号中
mysql> INSERT INTO tb_admin(id,username,`password`,createtime) VALUE
-> (7, 'Lily', 'Lily123456', NOW());
Query OK, 1 row affected (0.00 sec)
1.2 使用 INSERT…SET 语句插入数据
在 MySQL
中,除了可以使用 INSERT…VALUES
语句插入数据,还可以使用 INSERT…SET
语句。这种语法格式用于通过直接给表中的某些字段指定对应的值来实现插入指定数据,对于未指定值的字段将采用默认值进行添加。INSERT...SET
语句的语法格式如下:
参数说明如下:
[LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
:可选项,其作用与INSERT…VALUES
语句相同,这里不再赘述。[INTO]
数据表名:用于指定被操作的数据表,其中,[INTO]
为可选项,可以省略。SET字段名={值|DEFAULT}
:用于给数据表中的某些字段设置要插入的值。ON DUPLICATE KEY UPDATE
子句:可选项,其作用与INSERT…VALUES
语句相同,这里不再赘述。
示例4:通过INSERT…SET语句向数据表tb_admin中插入一条记录。
mysql> INSERT INTO tb_admin
-> SET id=8,username='Amo123',`password`='Amo123456',createtime=NOW();
Query OK, 1 row affected (0.00 sec)
1.3 使用 INSERT…SELECT 语句插入查询结果
在 MySQL
中,支持将查询结果插入指定的数据表中,这可以通过 INSERT...SELECT
语句来实现,其语法格式如下:
参数说明如下。
[LOW_PRIORITY|DELAYED|HIGH_PRIORITY] [IGNORE]
:可选项,其作用与INSERT...VALUES
语句相同,这里不再赘述。[INTO]
数据表名:用于指定被操作的数据表,其中,[INTO]
为可选项,可以省略。[(字段名,…)]
:可选项,当不指定该选项时,表示要向表中所有列插入数据,否则表示向数据表的指定列插入数据。SELECT
子句:用于快速地从一个或者多个表中取出数据,并将这些数据作为行数据插入目标数据表中。需要注意的是,SELECT
子句返回的结果集中的字段数、字段类型必须与目标数据表完全一致。ON DUPLICATE KEY UPDATE
子句:可选项,其作用与INSERT…VALUES
语句相同,这里不再赘述。
示例5:从数据表tb_admin中查询出id、username和password字段的值,插入数据表tb_admin2中。
mysql> #复制tb_admin表结构并给新表命名为 tb_admin2
mysql> DESC tb_admin2;
+------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+-------+
| id | int | NO | PRI | NULL | |
| username | varchar(40) | YES | | NULL | |
| password | varchar(30) | NO | | NULL | |
| createtime | datetime | YES | | NULL | |
+------------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
mysql> SELECT * FROM tb_admin2;
Empty set (0.00 sec)
mysql> INSERT INTO tb_admin2(id,username,password) SELECT id,username,password FROM tb_admin;
Query OK, 9 rows affected (0.00 sec)
Records: 9 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM tb_admin2;
+----+-----------+---------------+------------+
| id | username | password | createtime |
+----+-----------+---------------+------------+
| 1 | amo | 123456 | NULL |
| 2 | Jerry | Jerry123456 | NULL |
| 3 | Paul | Paul123456 | NULL |
| 4 | Ben | Ben123456 | NULL |
| 5 | Crystal | Crystal123456 | NULL |
| 6 | Jason | Jason123456 | NULL |
| 7 | Lily | Lily123456 | NULL |
| 8 | Amo1234 | Amo123456 | NULL |
| 9 | Amo123456 | Amo123456 | NULL |
+----+-----------+---------------+------------+
9 rows in set (0.00 sec)
二、修改(更新)数据
要执行修改的操作可以使用 UPDATE
语句,其语法如下:
参数说明如下:
[LOW_PRIORITY]
:可选项,表示在多用户访问数据库的情况下可用于延迟UPDATE
操作,直到没有别的用户再从表中读取数据为止。这个过程仅适用于表级锁的存储引擎(如 MyISAM、MEMORY 和 MERGE)。[IGNORE]
:在MySQL
中,通过UPDATE
语句更新表中多行数据时,如果出现错误,那么整个UPDATE
语句操作都会被取消,错误发生前更新的所有行将被恢复到它们原来的值。因此,为了在发生错误时也要继续进行更新,可以在UPDATE
语句中使用IGNORE
关键字。SET
子句:必选项,用于指定表中要修改的字段名及其字段值。其中的值可以是表达式,也可以是该字段所对应的默认值。如果要指定默认值,可使用关键字DEFAULT
。WHERE
子句:可选项,用于限定表中要修改的行,如果不指定该子句,那么UPDATE
语句会更新表中的所有行。ORDER BY
子句:可选项,用于限定表中的行被修改的次序。LIMIT
子句:可选项,用于限定被修改的行数。
示例6:将管理员信息表tb_admin2中用户名为amo的管理员密码123456修改为amo123。
注意: 更新时一定要保证 WHERE
子句的正确性,一旦 WHERE
子句出错,将会破坏所有改变的数据,所以在实际开发中最好是先使用 SELECT
查看 WHERE
子句的准确性,在使用 UPDATE
。
#如果省略WHERE 子句,则表中的所有数据都将被更新
#如果需要回滚数据,需要保证在DML前,进行设置: SET AUTOCOMMIT = FALSE;
mysql> UPDATE tb_admin2 SET password='amo123';
Query OK, 8 rows affected (0.00 sec)
Rows matched: 9 Changed: 8 Warnings: 0
mysql> SELECT * FROM tb_admin2;
+----+-----------+----------+------------+
| id | username | password | createtime |
+----+-----------+----------+------------+
| 1 | amo | amo123 | NULL |
| 2 | Jerry | amo123 | NULL |
| 3 | Paul | amo123 | NULL |
| 4 | Ben | amo123 | NULL |
| 5 | Crystal | amo123 | NULL |
| 6 | Jason | amo123 | NULL |
| 7 | Lily | amo123 | NULL |
| 8 | Amo1234 | amo123 | NULL |
| 9 | Amo123456 | amo123 | NULL |
+----+-----------+----------+------------+
9 rows in set (0.00 sec)
如果表中存在外键,更新中的数据可能会出现完整性错误,这个在后续讲解约束知识点的时候再进行演示,这里不再赘述,如下图所示:
三、删除数据
在数据库中,有些数据已经失去意义或者发生错误,此时需要将它们删除。在 MySQL
中,可以使用 DELETE
或者 TRUNCATE TABLE
语句删除表中的一行或多行数据,下面分别进行介绍。
3.1 通过 DELETE 语句删除数据
通过 DELETE 语句删除数据的基本语法格式如下:
参数说明如下:
[LOW_PRIORITY]
:可选项,表示在多用户访问数据库的情况下可用于延迟DELETE
操作,直到没有别的用户再从表中读取数据为止。这个过程仅适用于表级锁的存储引擎 (如MyISAM、MEMORY 和 MERGE)。[QUICK]
:可选项,用于加快部分种类的删除操作速度。[IGNORE]
:在MySQL
中,通过DELETE
语句删除表中多行数据时,如果出现错误,那么整个DELETE
语句操作都会被取消,错误发生前更新的所有行将被恢复到它们原来的值。因此,为了在发生错误时继续进行删除,可以在DELETE
语句中使用IGNORE
关键字。- 数据表名:用于指定要删除的数据表的名称。
WHERE
子句:可选项,用于限定表中要删除的行,如果不指定该子句,那么DELETE
语句会删除表中的所有行。ORDER BY
子句:可选项,用于限定表中的行被删除的次序。LIMIT
子句:可选项,用于限定被删除的行数。
示例7:删除管理员数据表tb_admin2中用户名为amo的记录信息。
mysql> DELETE FROM tb_admin2 WHERE username='amo';
Query OK, 1 row affected (0.00 sec)
#如果省略WHERE 子句,则表中的全部数据将被删除
mysql> DELETE FROM tb_admin2;
Query OK, 8 rows affected (0.00 sec)
mysql> SELECT * FROM tb_admin2;
Empty set (0.00 sec)
注意: 在实际的应用中,执行删除的条件一般应该为数据的 id(具有唯一性)
,而不是具体某个字段值,这样可以避免一些错误发生。删除中的数据完整性错误也会在后续讲解约束知识点时进行演示:
说明: You cannot delete a row that contains a primary key that is used as a foreign key in another table。
3.2 通过 TRUNCATE TABLE 语句删除数据
如果要删除表中所有的行,可通过 TRUNCATE TABLE
语句实现,其基本语法格式如下:
TRUNCATE [TABLE] 数据表名
在上面的语法中,数据表名表示删除的数据表的名称,也可以使用 数据库名.数据表名
来指定该数据表隶属于哪个数据库。
示例8:使用TRUNCATE TABLE语句清空管理员数据表tb_admin。
mysql> TRUNCATE TABLE db_admin.tb_admin;
Query OK, 0 rows affected (0.01 sec)
mysql> SELECT * FROM tb_admin;
Empty set (0.00 sec)
注意: 由于 TRUNCATE TABLE
语句会删除数据表中的所有数据,并且无法恢复,因此使用 TRUNCATE TABLE
语句时一定要十分小心。无论是使用 DELETE
或者是 TRUNCATE
都表示清空或者删除表中的数据,仍保留表的数据结构。
3.3 DELETE 语句和 TRUNCATE TABLE 语句的区别
说明:
TRUNCATE TABLE
在功能上与不带WHERE
子句的DELETE FROM
语句相同。都可以实现对表中所有数据的删除,同时保留表结构。
不同点:TRUNCATE TABLE
:一旦执行此操作,表数据全部清除。同时,数据是不可以回滚的。
DELETE FROM
:一旦执行此操作,表数据可以全部清除(不带WHERE
)。同时,数据是可以实现回滚的。
(1) 使用 TRUNCATE TABLE
语句后,表中的 AUTO_INCREMENT
计数器将被重新设置为该列的初始值。示例如下所示:
#创建测试表
mysql> CREATE TABLE tb_admin1(
-> id INT PRIMARY KEY AUTO_INCREMENT,
-> `user` VARCHAR(30) NOT NULL,
-> `password` VARCHAR(30) NOT NULL,
-> createtime DATETIME);
Query OK, 0 rows affected (0.01 sec)
mysql> show tables;
+--------------------+
| Tables_in_db_admin |
+--------------------+
| tb_admin |
| tb_admin1 |
| tb_admin2 |
+--------------------+
3 rows in set (0.00 sec)
mysql> drop table tb_admin2;
Query OK, 0 rows affected (0.01 sec)
mysql> show tables;
+--------------------+
| Tables_in_db_admin |
+--------------------+
| tb_admin |
| tb_admin1 |
+--------------------+
2 rows in set (0.00 sec)
mysql> INSERT INTO tb_admin1(user, password) VALUES('amo', 'amo123');
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO tb_admin1(user, password) VALUES('amo1', 'amo123');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT * FROM tb_admin1;
+----+------+----------+------------+
| id | user | password | createtime |
+----+------+----------+------------+
| 1 | amo | amo123 | NULL |
| 2 | amo1 | amo123 | NULL |
+----+------+----------+------------+
2 rows in set (0.00 sec)
mysql> TRUNCATE TABLE tb_admin1;
Query OK, 0 rows affected (0.01 sec)
mysql> SELECT * FROM tb_admin1;
Empty set (0.00 sec)
mysql> INSERT INTO tb_admin1(user, password) VALUES('amo', 'amo123');
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO tb_admin1(user, password) VALUES('amo123', 'amo123');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT * FROM tb_admin1;
+----+--------+----------+------------+
| id | user | password | createtime |
+----+--------+----------+------------+
| 1 | amo | amo123 | NULL |
| 2 | amo123 | amo123 | NULL |
+----+--------+----------+------------+
2 rows in set (0.00 sec)
mysql> DELETE FROM tb_admin1;
Query OK, 2 rows affected (0.00 sec)
mysql> SELECT * FROM tb_admin1;
Empty set (0.00 sec)
mysql> INSERT INTO tb_admin1(user, password) VALUES('amo123', 'amo123');
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO tb_admin1(user, password) VALUES('amo', 'amo123');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT * FROM tb_admin1;
+----+--------+----------+------------+
| id | user | password | createtime |
+----+--------+----------+------------+
| 3 | amo123 | amo123 | NULL |
| 4 | amo | amo123 | NULL |
+----+--------+----------+------------+
2 rows in set (0.00 sec)
(2) TRUNCATE TABLE
操作比 DELETE
操作使用的系统和事务日志资源少。DELETE
语句每删除一行都会在事务日志中添加一行记录,而 TRUNCATE TABLE
语句是通过释放存储表数据所用的数据页来删除数据的,因此只在事务日志中记录页的释放。
阿里开发规范 【参考】:
TRUNCATE TABLE
比DELETE
速度快,且使用的系统和事务日志资源少,但TRUNCATE
无事务且不触发TRIGGER
,有可能造成事故,故不建议在开发代码中使用此语句。
(3) 对于参与了索引和视图的表,不能使用 TRUNCATE TABLE
语句来删除数据,而应该使用 DELETE
语句。
3.4 补充: DCL 中 COMMIT 和 ROLLBACK
COMMIT
:提交数据。一旦执行 COMMIT
,则数据就被永久的保存在了数据库中,意味着数据不可以回滚。
ROLLBACK
:回滚数据。一旦执行 ROLLBACK
,则可以实现数据的回滚。回滚到最近的一次 COMMIT
之后。对比 TRUNCATE TABLE
和 DELETE FROM
,演示 DELETE FROM
如下所示:
mysql> COMMIT;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT * FROM tb_admin1;
+----+--------+----------+------------+
| id | user | password | createtime |
+----+--------+----------+------------+
| 3 | amo123 | amo123 | NULL |
| 4 | amo | amo123 | NULL |
+----+--------+----------+------------+
2 rows in set (0.00 sec)
mysql> SET autocommit = FALSE;
Query OK, 0 rows affected (0.00 sec)
mysql> DELETE FROM tb_admin1;
Query OK, 2 rows affected (0.00 sec)
mysql> SELECT * FROM tb_admin1;
Empty set (0.00 sec)
mysql> ROLLBACK;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT * FROM tb_admin1;
+----+--------+----------+------------+
| id | user | password | createtime |
+----+--------+----------+------------+
| 3 | amo123 | amo123 | NULL |
| 4 | amo | amo123 | NULL |
+----+--------+----------+------------+
2 rows in set (0.00 sec)
演示 TRUNCATE TABLE
如下所示:
mysql> COMMIT;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT * FROM tb_admin1;
+----+--------+----------+------------+
| id | user | password | createtime |
+----+--------+----------+------------+
| 3 | amo123 | amo123 | NULL |
| 4 | amo | amo123 | NULL |
+----+--------+----------+------------+
2 rows in set (0.00 sec)
mysql> SET autocommit = FALSE;
Query OK, 0 rows affected (0.00 sec)
mysql> TRUNCATE TABLE tb_admin1;
Query OK, 0 rows affected (0.01 sec)
mysql> SELECT * FROM tb_admin1;
Empty set (0.00 sec)
mysql> ROLLBACK;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT * FROM tb_admin1;
Empty set (0.00 sec)
3.5 补充: MySQL8新特性:计算列
什么叫计算列呢?简单来说就是某一列的值是通过别的列计算得来的。例如,a
列值为1、b
列值为2,c
列不需要手动插入,定义 a+b
的结果为 c
的值,那么 c
就是计算列,是通过别的列计算得来的。在 MySQL 8.0
中,CREATE TABLE
和 ALTER TABLE
中都支持增加计算列。下面以 CREATE TABLE
为例进行讲解。举例:定义数据表 tb1
,然后定义字段 id
、字段 a
、字段 b
和字段 c
,其中字段 c
为计算列,用于计算 a+b
的值。 示例如下:
mysql> CREATE TABLE tb1(
-> id INT, a INT, b INT,
-> c INT GENERATED ALWAYS AS (a + b) VIRTUAL
-> );
Query OK, 0 rows affected (0.01 sec)
mysql> INSERT INTO tb1(a, b) VALUES(10, 20);
Query OK, 1 row affected (0.01 sec)
mysql> SELECT * FROM tb1;
+------+------+------+------+
| id | a | b | c |
+------+------+------+------+
| NULL | 10 | 20 | 30 |
+------+------+------+------+
1 row in set (0.00 sec)
mysql> #更新数据中的数据,语句如下:
mysql> UPDATE tb1 SET a=40;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> SELECT * FROM tb1;
+------+------+------+------+
| id | a | b | c |
+------+------+------+------+
| NULL | 40 | 20 | 60 |
+------+------+------+------+
1 row in set (0.00 sec)
3.6 小结
本文介绍了在 MySQL
中添加、修改和删除表数据的具体方法,也就是对表数据的增、删和改操作。这3种操作在实际开发中经常应用。因此,读者需要认真学习本文的内容,争取做到举一反三、灵活应用。
四、综合练习
练习1:创建数据库test01_library。
mysql> CREATE DATABASE IF NOT EXISTS test01_library CHARACTER SET = 'utf8mb4';
Query OK, 1 row affected (0.00 sec)
mysql> USE test01_library;
Database changed
练习2:创建表 books,表结构如下:
字段名 | 字段说明 | 数据类型 |
---|---|---|
id | 书编号 | INT |
name | 书名 | VARCHAR(50) |
authors | 作者 | VARCHAR(100) |
price | 价格 | FLOAT |
pubdate | 出版日期 | YEAR |
note | 说明 | VARCHAR(100) |
num | 库存 | INT |
SQL 语句如下:
mysql> CREATE TABLE IF NOT EXISTS books(
-> id INT COMMENT '图书编号',
-> `name` VARCHAR(50) COMMENT '书名',
-> `authors` VARCHAR(100) COMMENT '作者',
-> price FLOAT COMMENT '价格',
-> pubdate YEAR COMMENT '出版日期',
-> note VARCHAR(100) COMMENT '说明',
-> num INT COMMENT '库存');
Query OK, 0 rows affected (0.01 sec)
mysql> SHOW TABLES;
+--------------------------+
| Tables_in_test01_library |
+--------------------------+
| books |
+--------------------------+
1 row in set (0.00 sec)
mysql> DESC books;
+---------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+--------------+------+-----+---------+-------+
| id | int | YES | | NULL | |
| name | varchar(50) | YES | | NULL | |
| authors | varchar(100) | YES | | NULL | |
| price | float | YES | | NULL | |
| pubdate | year | YES | | NULL | |
| note | varchar(100) | YES | | NULL | |
| num | int | YES | | NULL | |
+---------+--------------+------+-----+---------+-------+
7 rows in set (0.00 sec)
练习3:向books表中插入记录。
id | name | authors | price | pubdate | note | num |
---|---|---|---|---|---|---|
1 | Tal of AAA | Dickes | 23 | 1995 | novel | 11 |
2 | EmmaT | Jane lura | 35 | 1993 | joke | 22 |
3 | Story of Jane | Jane Tim | 40 | 2001 | novel | 0 |
4 | Lovey Day | George Byron | 20 | 2005 | novel | 30 |
5 | Old land | Honore Blade | 30 | 2010 | law | 0 |
6 | The Battle | Upton Sara | 30 | 1999 | medicine | 40 |
7 | Rose Hood | Richard haggard | 28 | 2008 | cartoon | 28 |
SQL 语句如下:
#1.不指定字段名称,插入第一条记录
mysql> INSERT INTO books
-> VALUES(1,'Tal of AAA','Dickes',23,'1995','novel',11);
Query OK, 1 row affected (0.00 sec)
#2.指定所有字段名称,插入第二记录
mysql> INSERT INTO books(id,NAME,AUTHORS,price,pubdate,note,num)
-> VALUES(2,'EmmaT','Jane lura',35,'1993','joke',22);
Query OK, 1 row affected (0.00 sec)
#3.同时插入多条记录(剩下的所有记录)
mysql> INSERT INTO books(id,NAME,AUTHORS,price,pubdate,note,num)
-> VALUES
-> (3,'Story of Jane','Jane Tim',40,2001,'novel',0),
-> (4,'Lovey Day','George Byron',20,2005,'novel',30),
-> (5,'Old land','Honore Blade',30,2010,'Law',0),
-> (6,'The Battle','Upton Sara',30,1999,'medicine',40),
-> (7,'Rose Hood','Richard haggard',28,2008,'cartoon',28);
Query OK, 5 rows affected (0.00 sec)
Records: 5 Duplicates: 0 Warnings: 0
练习4:将小说类型(novel)的书的价格都增加5。
mysql> UPDATE books SET price=price+5 WHERE note='novel';
Query OK, 3 rows affected (0.00 sec)
Rows matched: 3 Changed: 3 Warnings: 0
练习5:将名称为EmmaT的书的价格改为40,并将说明改为drama。
mysql> UPDATE books SET price=40,note='drama' WHERE name='EmmaT';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
练习6:删除库存为0的记录。
mysql> DELETE FROM books WHERE num=0;
Query OK, 2 rows affected (0.00 sec)
mysql> SELECT * FROM books;
+------+------------+-----------------+-------+---------+----------+------+
| id | name | authors | price | pubdate | note | num |
+------+------------+-----------------+-------+---------+----------+------+
| 1 | Tal of AAA | Dickes | 28 | 1995 | novel | 11 |
| 2 | EmmaT | Jane lura | 40 | 1993 | drama | 22 |
| 4 | Lovey Day | George Byron | 25 | 2005 | novel | 30 |
| 6 | The Battle | Upton Sara | 30 | 1999 | medicine | 40 |
| 7 | Rose Hood | Richard haggard | 28 | 2008 | cartoon | 28 |
+------+------------+-----------------+-------+---------+----------+------+
5 rows in set (0.00 sec)
练习7:统计书名中包含a字母的书。
mysql> SELECT name FROM books WHERE name LIKE '%a%';
+------------+
| name |
+------------+
| Tal of AAA |
| EmmaT |
| Lovey Day |
| The Battle |
+------------+
4 rows in set (0.00 sec)
练习8:统计书名中包含a字母的书的数量和库存总量。
mysql> SELECT COUNT(name), SUM(num) FROM books WHERE name LIKE '%a%';
+-------------+----------+
| COUNT(name) | SUM(num) |
+-------------+----------+
| 4 | 103 |
+-------------+----------+
1 row in set (0.00 sec)
练习9:统计书名中包含a字母的书的数量和库存总量。
mysql> SELECT COUNT(name), SUM(num) FROM books WHERE name LIKE '%a%';
+-------------+----------+
| COUNT(name) | SUM(num) |
+-------------+----------+
| 4 | 103 |
+-------------+----------+
1 row in set (0.00 sec)
练习10:找出“novel”类型的书,按照价格降序排列。
mysql> SELECT * FROM books WHERE note='novel' ORDER BY price DESC;
+------+------------+--------------+-------+---------+-------+------+
| id | name | authors | price | pubdate | note | num |
+------+------------+--------------+-------+---------+-------+------+
| 1 | Tal of AAA | Dickes | 28 | 1995 | novel | 11 |
| 4 | Lovey Day | George Byron | 25 | 2005 | novel | 30 |
+------+------------+--------------+-------+---------+-------+------+
2 rows in set (0.00 sec)
练习11:查询图书信息,按照库存量降序排列,如果库存量相同的按照note升序排列。
mysql> SELECT * FROM books ORDER BY num DESC, name ASC;
+------+------------+-----------------+-------+---------+----------+------+
| id | name | authors | price | pubdate | note | num |
+------+------------+-----------------+-------+---------+----------+------+
| 6 | The Battle | Upton Sara | 30 | 1999 | medicine | 40 |
| 4 | Lovey Day | George Byron | 25 | 2005 | novel | 30 |
| 7 | Rose Hood | Richard haggard | 28 | 2008 | cartoon | 28 |
| 2 | EmmaT | Jane lura | 40 | 1993 | drama | 22 |
| 1 | Tal of AAA | Dickes | 28 | 1995 | novel | 11 |
+------+------------+-----------------+-------+---------+----------+------+
5 rows in set (0.00 sec)
练习12:按照note分类统计书的数量。
mysql> SELECT note,COUNT(*) FROM books GROUP BY note;
+----------+----------+
| note | COUNT(*) |
+----------+----------+
| novel | 2 |
| drama | 1 |
| medicine | 1 |
| cartoon | 1 |
+----------+----------+
4 rows in set (0.00 sec)
练习13:按照note分类统计书的库存量,显示库存量超过30本的。
mysql> SELECT note,SUM(num) FROM books GROUP BY note HAVING SUM(num)>30;
+----------+----------+
| note | SUM(num) |
+----------+----------+
| novel | 41 |
| medicine | 40 |
+----------+----------+
2 rows in set (0.00 sec)
练习14:查询所有图书,每页显示5本,显示第二页。
mysql> SELECT *
-> FROM books
-> LIMIT 5,5;
Empty set (0.00 sec)
练习15:按照note分类统计书的库存量,显示库存量最多的。
mysql> SELECT note,SUM(num) "sum_num" FROM books GROUP BY note ORDER BY sum_num DESC LIMIT 1;
+-------+---------+
| note | sum_num |
+-------+---------+
| novel | 41 |
+-------+---------+
1 row in set (0.00 sec)
练习16:查询书名达到9个字符的书,不包括里面的空格。
mysql> SELECT * FROM books WHERE CHAR_LENGTH(REPLACE(name, ' ', ''))>=9;
+------+------------+------------+-------+---------+----------+------+
| id | name | authors | price | pubdate | note | num |
+------+------------+------------+-------+---------+----------+------+
| 6 | The Battle | Upton Sara | 30 | 1999 | medicine | 40 |
+------+------------+------------+-------+---------+----------+------+
1 row in set (0.00 sec)
练习17:查询书名和类型,其中note值为novel显示小说,law显示法律,medicine显示医药,cartoon显示卡通,joke显示笑话。
mysql> SELECT name "书名",note, CASE note WHEN 'novel' THEN '小说'
-> WHEN 'law' THEN '法律'
-> WHEN 'medicine' THEN '医药'
-> WHEN 'cartoon' THEN '卡通'
-> WHEN 'joke' THEN '笑话'
-> ELSE '其他'
-> END "类型" FROM books;
+------------+----------+------+
| 书名 | note | 类型 |
+------------+----------+------+
| Tal of AAA | novel | 小说 |
| EmmaT | drama | 其他 |
| Lovey Day | novel | 小说 |
| The Battle | medicine | 医药 |
| Rose Hood | cartoon | 卡通 |
+------------+----------+------+
5 rows in set (0.00 sec)
练习18:查询书名、库存,其中num值超过30本的,显示滞销,大于0并低于10的,显示畅销,为0的显示需要无货。
mysql> SELECT name "书名", num "库存", CASE WHEN num > 30 THEN '滞销'
-> WHEN num > 0 AND num < 10 THEN '畅销'
-> WHEN num = 0 THEN '无货'
-> ELSE '正常'
-> END "显示状态" FROM books;
+------------+------+----------+
| 书名 | 库存 | 显示状态 |
+------------+------+----------+
| Tal of AAA | 11 | 正常 |
| EmmaT | 22 | 正常 |
| Lovey Day | 30 | 正常 |
| The Battle | 40 | 滞销 |
| Rose Hood | 28 | 正常 |
+------------+------+----------+
5 rows in set (0.00 sec)
练习19:统计每一种note的库存量,并合计总量。
mysql> SELECT IFNULL(note,'合计库存总量') AS note,SUM(num)
-> FROM books
-> GROUP BY note WITH ROLLUP;
+--------------+----------+
| note | SUM(num) |
+--------------+----------+
| cartoon | 28 |
| drama | 22 |
| medicine | 40 |
| novel | 41 |
| 合计库存总量 | 131 |
+--------------+----------+
5 rows in set, 1 warning (0.00 sec)
练习20:统计每一种note的数量,并合计总量。
mysql> SELECT IFNULL(note,'合计总量') AS note,COUNT(*)
-> FROM books
-> GROUP BY note WITH ROLLUP;
+----------+----------+
| note | COUNT(*) |
+----------+----------+
| cartoon | 1 |
| drama | 1 |
| medicine | 1 |
| novel | 2 |
| 合计总量 | 5 |
+----------+----------+
5 rows in set, 1 warning (0.00 sec)
练习21:统计库存量前三名的图书。
mysql> SELECT * FROM books ORDER BY num DESC LIMIT 3;
+------+------------+-----------------+-------+---------+----------+------+
| id | name | authors | price | pubdate | note | num |
+------+------------+-----------------+-------+---------+----------+------+
| 6 | The Battle | Upton Sara | 30 | 1999 | medicine | 40 |
| 4 | Lovey Day | George Byron | 25 | 2005 | novel | 30 |
| 7 | Rose Hood | Richard haggard | 28 | 2008 | cartoon | 28 |
+------+------------+-----------------+-------+---------+----------+------+
3 rows in set (0.00 sec)
练习22:找出最早出版的一本书。
mysql> SELECT *
-> FROM books
-> ORDER BY pubdate ASC
-> LIMIT 0,1;
+------+-------+-----------+-------+---------+-------+------+
| id | name | authors | price | pubdate | note | num |
+------+-------+-----------+-------+---------+-------+------+
| 2 | EmmaT | Jane lura | 40 | 1993 | drama | 22 |
+------+-------+-----------+-------+---------+-------+------+
1 row in set (0.00 sec)
练习23:找出novel中价格最高的一本书。
mysql> SELECT *
-> FROM books
-> WHERE note = 'novel'
-> ORDER BY price DESC
-> LIMIT 0,1;
+------+------------+---------+-------+---------+-------+------+
| id | name | authors | price | pubdate | note | num |
+------+------------+---------+-------+---------+-------+------+
| 1 | Tal of AAA | Dickes | 28 | 1995 | novel | 11 |
+------+------------+---------+-------+---------+-------+------+
1 row in set (0.00 sec)
练习24:找出书名中字数最多的一本书,不含空格。
mysql> SELECT *
-> FROM books
-> ORDER BY CHAR_LENGTH(REPLACE(NAME,' ','')) DESC
-> LIMIT 0,1;
+------+------------+------------+-------+---------+----------+------+
| id | name | authors | price | pubdate | note | num |
+------+------------+------------+-------+---------+----------+------+
| 6 | The Battle | Upton Sara | 30 | 1999 | medicine | 40 |
+------+------------+------------+-------+---------+----------+------+
1 row in set (0.00 sec)
至此今天的学习就到此结束了,笔者在这里声明,笔者写文章只是为了学习交流,以及让更多学习数据库的读者少走一些弯路,节省时间,并不用做其他用途,如有侵权,联系博主删除即可。感谢您阅读本篇博文,希望本文能成为您编程路上的领航者。祝您阅读愉快!
好书不厌读百回,熟读课思子自知。而我想要成为全场最靓的仔,就必须坚持通过学习来获取更多知识,用知识改变命运,用博客见证成长,用行动证明我在努力。
如果我的博客对你有帮助、如果你喜欢我的博客内容,请点赞
、评论
、收藏
一键三连哦!听说点赞的人运气不会太差,每一天都会元气满满呦!如果实在要白嫖的话,那祝你开心每一天,欢迎常来我博客看看。
编码不易,大家的支持就是我坚持下去的动力。点赞后不要忘了关注
我哦!
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)