MySQL 8.0——插入、更新与删除数据

插入、更新与删除数据

1、插入数据

在使用数据库之前,数据库中必须要有数据,MySQL中使用INSERT语句向数据库表中插入新的数据记录。可以插入的方式有插入完整的记录、插入记录的一部分、插入多条记录、插入另一个查询的结果,下面将分别介绍这些内容。

1.1、为表的所有字段插入数据

使用基本的INSERT语句插入数据要求指定表名称和插入到新记录中的值。基本语法格式为:

sql 复制代码
INSERT INTO table_name (column_list) 
VALUES (value_list);
  • table_name指定要插入数据的表名
  • column_list指定要插入数据的那些列
  • value_list指定每个列应对应插入的数据。

注意,使用该语句时字段列和数据值的数量必须相同。

样例表person,创建语句如下:

sql 复制代码
create table person
(
	id int unsigned not null auto_increment,
	name char(40) not null default '',
	age int not null default 0,
	info char(50) null,
	primary key (id)
);

向表中所有字段插入值的方法有两种:

  • 一种是指定所有字段名
  • 另一种是完全不指定字段名

在person表中,插入一条新记录,id值为1,name值为Green,age值为21,info值为Lawyer,SQL语句如下:

执行插入操作之前,使用SELECT语句查看表中的数据:

sql 复制代码
select * from person;

+----+------+-----+------+
| id | name | age | info |
+----+------+-----+------+
+----+------+-----+------+

结果显示当前表为空,没有数据,接下来执行插入操作:

sql 复制代码
insert into person (id, name, age, info)
values (1, 'Green', 21, 'Lawyer');

可以看到插入记录成功。在插入数据时,指定了person表的所有字段,因此将为每一个字段插入新的值。

INSERT语句后面的列名称顺序可以不是person表定义时的顺序。即插入数据时,不需要按照表定义的顺序插入,只要保证值的顺序与列字段的顺序相同就可以。

在person表中,插入一条新记录,id值为2,name值为Suse,age值为22,info值为dancer,SQL语句如下:

sql 复制代码
insert into person(age, name, id, info)
values (22, 'Suse', 2, 'dancer');

语句执行完毕,查看执行结果:

sql 复制代码
select * from person;

+----+-------+-----+--------+
| id | name  | age | info   |
+----+-------+-----+--------+
|  1 | Green |  21 | Lawyer |
|  2 | Suse  |  22 | dancer |
+----+-------+-----+--------+

由结果可以看到,INSERT语句成功插入了一条记录。

使用INSERT插入数据时,允许列名称列表column_list为空,此时,值列表中需要为表的每一个字段指定值,并且值的顺序必须和数据表中字段定义时的顺序相同

在person表中,插入一条新记录,id值为3,name值为Mary,age值为24,info值为Musician,SQL语句如下:

sql 复制代码
INSERT INTO person
VALUES (3,'Mary', 24, 'Musician');

可以看到插入记录成功。数据库中增加了一条id为3的记录,其他字段值为指定的插入值。本例的INSERT语句中没有指定插入列表,只有一个值列表。在这种情况下,值列表为每一个字段列指定插入值,并且这些值的顺序必须和person表中字段定义的顺序相同。

虽然使用INSERT插入数据时可以忽略插入数据的列名称,但是值如果不包含列名称,那么VALUES关键字后面的值不仅要求完整而且顺序必须和表定义时列的顺序相同。如果表的结构被修改,对列进行增加、删除或者位置改变操作,这些操作将使得用这种方式插入数据时的顺序也同时改变。如果指定列名称,则不会受到表结构改变的影响。

1.2、为表的指定字段插入数据

为表的指定字段插入数据,就是在INSERT语句中只向部分字段中插入值,而其他字段的值为表定义时的默认值。

在person表中,插入一条新记录,name值为Willam,age值为20,info值为sportsman,SQL语句如下:

sql 复制代码
insert into person(name, age, info)
values('Willam', 20, 'sports man');

提示信息表示插入一条记录成功。使用SELECT查询表中的记录,查询结果如下:

sql 复制代码
select * from person;

+----+--------+-----+------------+
| id | name   | age | info       |
+----+--------+-----+------------+
|  1 | Green  |  21 | Lawyer     |
|  2 | Suse   |  22 | dancer     |
|  3 | Mary   |  24 | Musician   |
|  4 | Willam |  20 | sports man |
+----+--------+-----+------------+

可以看到插入记录成功。如查询结果显示,该id字段自动添加了一个整数值4。在这里,id字段为表的主键,不能为空,系统会自动为该字段插入自增的序列值。在插入记录时,如果某些字段没有指定插入值,MySQL将插入该字段定义时的默认值。下面的例子说明在没有指定列字段时,插入默认值。

在person表中,插入一条新记录,name值为laura,age值为25,SQL语句如下:

sql 复制代码
insert into person(name, age)
values('Laura', 25);

语句执行完毕,查看执行结果:

sql 复制代码
select * from person;

+----+--------+-----+------------+
| id | name   | age | info       |
+----+--------+-----+------------+
|  1 | Green  |  21 | Lawyer     |
|  2 | Suse   |  22 | dancer     |
|  3 | Mary   |  24 | Musician   |
|  4 | Willam |  20 | sports man |
|  5 | Laura  |  25 | <null>     |
+----+--------+-----+------------+

可以看到,在本例插入语句中,没有指定info字段值,查询结果显示,info字段在定义时默认为NULL,因此系统自动为该字段插入空值。

要保证每个插入值的类型和对应列的数据类型匹配,如果类型不同,将无法插入,并且MySQL会产生错误。

1.3、同时插入多条记录

INSERT语句可以同时向数据表中插入多条记录,插入时指定多个值列表,每个值列表之间用逗号分隔开,基本语法格式如下:

sql 复制代码
insert into table_name (column_list)
values (value_list1), (values_list2),...(value_listn);

"value_list1,value_list2,...,value_listn"表示第1,2,...,n个插入记录的字段的值列表。

在person表中,在name、age和info字段指定插入值,同时插入3条新记录,SQL语句如下:

sql 复制代码
insert into person(name, age, info) values
('Evans', 27, 'secretary'),
('Dale', 22, 'cook'),
('Edison', 28, 'singer');

语句执行完毕,查看执行结果:

sql 复制代码
select * from person;

+----+--------+-----+------------+
| id | name   | age | info       |
+----+--------+-----+------------+
|  1 | Green  |  21 | Lawyer     |
|  2 | Suse   |  22 | dancer     |
|  3 | Mary   |  24 | Musician   |
|  4 | Willam |  20 | sports man |
|  5 | Laura  |  25 | <null>     |
|  6 | Evans  |  27 | secretary  |
|  7 | Dale   |  22 | cook       |
|  8 | Edison |  28 | singer     |
+----+--------+-----+------------+

由结果可以看到,INSERT语句执行后,person表中添加了3条记录,其name和age字段分别为指定的值,id字段为MySQL添加的默认的自增值。

使用INSERT同时插入多条记录时,MySQL会返回一些在执行单行插入时没有的额外信息,这些信息的含义如下:

  • Records:表明插入的记录条数。
  • Duplicates:表明插入时被忽略的记录,原因可能是这些记录包含了重复的主键值。
  • Warnings:表明有问题的数据值,例如发生数据类型转换。

在person表中,不指定插入列表,同时插入2条新记录,SQL语句如下:

sql 复制代码
insert into person values
(9, 'Harry', 21, 'magician'),
(null, 'Harriet', 19, 'painist');

语句执行结果如下:

sql 复制代码
Query OK, 2 rows affected
Time: 0.073s

语句执行完毕,查看执行结果:

sql 复制代码
select * from person;

+----+---------+-----+------------+
| id | name    | age | info       |
+----+---------+-----+------------+
|  1 | Green   |  21 | Lawyer     |
|  2 | Suse    |  22 | dancer     |
|  3 | Mary    |  24 | Musician   |
|  4 | Willam  |  20 | sports man |
|  5 | Laura   |  25 | <null>     |
|  6 | Evans   |  27 | secretary  |
|  7 | Dale    |  22 | cook       |
|  8 | Edison  |  28 | singer     |
|  9 | Harry   |  21 | magician   |
| 10 | Harriet |  19 | painist    |
+----+---------+-----+------------+

由结果可以看到,INSERT语句执行后,person表中添加了2条记录,与前面介绍单个INSERT语法不同,person表名后面没有指定插入字段列表,因此VALUES关键字后面的多个值列表都要为每一条记录的每一个字段列指定插入值,并且这些值的顺序必须和person表中字段定义的顺序相同,带有AUTO_INCREMENT属性的id字段插入NULL值,系统会自动为该字段插入唯一的自增编号。

一个同时插入多行记录的INSERT语句等同于多个单行插入的INSERT语句,但是多行的INSERT语句在处理过程中效率更高。因为MySQL执行单条INSERT语句插入多行数据比使用多条INSERT语句快,所以在插入多条记录时最好选择使用单条INSERT语句的方式插入。

1.4、将查询结果插入到表中

INSERT语句用来给数据表插入记录时指定插入记录的列值。INSERT还可以将SELECT语句查询的结果插入到表中,如果想要从另外一个表中合并个人信息到person表,不需要把每一条记录的值一个一个输入,只需要使用一条INSERT语句和一条SELECT语句组成的组合语句即可快速地从一个或多个表中向一个表中插入多行。基本语法格式如下:

sql 复制代码
INSERT INTO table_name1 (column_list1)
SELECT (column_list2) 
FROM table_name2 
WHERE (condition)

table_name1指定待插入数据的表;column_list1指定待插入表中要插入数据的哪些列;table_name2指定插入数据是从哪个表中查询出来的;column_list2指定数据来源表的查询列,该列表必须和column_list1列表中的字段个数相同,数据类型相同;condition指定SELECT语句的查询条件。

从person_old表中查询所有的记录,并将其插入到person表中。

首先,创建一个名为person_old的数据表,其表结构与person结构相同,SQL语句如下:

sql 复制代码
create table person_old
(
	id int unsigned not null auto_increment,
	name char(40) not null default '',
	age int not null default 0,
	info char(50) null,
	primary key(id)
);

可以看到,插入记录成功,peson_old表中现在有两条记录。接下来将person_old表中所有的记录插入person表中,SQL语句如下:

sql 复制代码
INSERT INTO person(id, name, age, info)
SELECT id, name, age, info FROM person_old;

语句执行完毕,查看执行结果:

sql 复制代码
select * from person;

+----+---------+-----+------------+
| id | name    | age | info       |
+----+---------+-----+------------+
|  1 | Green   |  21 | Lawyer     |
|  2 | Suse    |  22 | dancer     |
|  3 | Mary    |  24 | Musician   |
|  4 | Willam  |  20 | sports man |
|  5 | Laura   |  25 | <null>     |
|  6 | Evans   |  27 | secretary  |
|  7 | Dale    |  22 | cook       |
|  8 | Edison  |  28 | singer     |
|  9 | Harry   |  21 | magician   |
| 10 | Harriet |  19 | painist    |
+----+---------+-----+------------+

由结果可以看到,INSERT语句执行后,person表中多了两条记录,这两条记录和person_old表中的记录完全相同,数据转移成功。这里的id字段为自增的主键,在插入的时候要保证该字段值的唯一性,如果不能确定,可以在插入的时候忽略该字段,只插入其他字段的值。

2、更新数据

表中有数据之后,接下来可以对数据进行更新操作,MySQL中使用UPDATE语句更新表中的记录,可以更新特定的行或者同时更新所有的行。基本语法结构如下:

sql 复制代码
update table_name
set column_name1 = value1, column_name2 = value2, ..., column_namen = valuen
where )condition);

column_name1,column_name2,......,column_namen为指定更新的字段的名称;value1,value2,......,valuen为相对应的指定字段的更新值;condition指定更新的记录需要满足的条件。更新多列时,每个"列-值"对之间用逗号隔开,最后一列之后不需要逗号。

在person表中,更新id值为10的记录,将age字段值改为15,将name字段值改为LiMing,SQL语句如下:

sql 复制代码
UPDATE person SET age = 15, name='LiMing' WHERE id = 10;

语句执行完毕,查看执行结果:

sql 复制代码
select * from person 
where id = 10;

+----+--------+-----+---------+
| id | name   | age | info    |
+----+--------+-----+---------+
| 10 | LiMing |  15 | painist |
+----+--------+-----+---------+

由结果可以看到,id等于10的记录中的name和age字段的值已经成功地被修改为指定值。

保证UPDATE以WHERE子句结束,通过WHERE子句指定被更新的记录所需要满足的条件,如果忽略WHERE子句,MySQL将更新表中所有的行。

在person表中,更新age值为19~22的记录,将info字段值都改为student,SQL语句如下:

sql 复制代码
update person set info = 'student'
where age between 19 and 22;

语句执行完毕,查看执行结果:

sql 复制代码
select * from person;

+----+--------+-----+-----------+
| id | name   | age | info      |
+----+--------+-----+-----------+
|  1 | Green  |  21 | student   |
|  2 | Suse   |  22 | student   |
|  3 | Mary   |  24 | Musician  |
|  4 | Willam |  20 | student   |
|  5 | Laura  |  25 | <null>    |
|  6 | Evans  |  27 | secretary |
|  7 | Dale   |  22 | student   |
|  8 | Edison |  28 | singer    |
|  9 | Harry  |  21 | student   |
| 10 | LiMing |  15 | painist   |
+----+--------+-----+-----------+

由结果可以看到,UPDATE执行后,成功将表中符合条件的6条记录的info字段值都改为student。

3、删除数据

从数据表中删除数据使用DELETE语句,DELETE语句允许WHERE子句指定删除条件。DELETE语句基本语法格式如下:

sql 复制代码
DELETE FROM table_name [WHERE <condition>];

table_name指定要执行删除操作的表;​"​WHERE ​"为可选参数,指定删除条件,如果没有WHERE子句,DELETE语句将删除表中的所有记录。

在person表中,删除id等于10的记录,SQL语句如下:

执行删除操作前,使用SELECT语句查看当前id=10的记录:

sql 复制代码
select * from person 
where id = 10;

+----+--------+-----+---------+
| id | name   | age | info    |
+----+--------+-----+---------+
| 10 | LiMing |  15 | painist |
+----+--------+-----+---------+

可以看到,现在表中有id=10的记录。下面使用DELETE语句删除该记录:

sql 复制代码
delete from person 
where id = 10;

语句执行完毕,查看执行结果:

sql 复制代码
select * from person 
where id = 10;

+----+------+-----+------+
| id | name | age | info |
+----+------+-----+------+
+----+------+-----+------+

查询结果为空,说明删除操作成功。

在person表中,使用DELETE语句同时删除多条记录。在前面UPDATE语句中将age字段值在19~22之间的记录的info字段值修改为student,在这里删除这些记录。

执行删除操作前,使用SELECT语句查看当前的数据:

sql 复制代码
select * from person 
where age between 19 and 22;

+----+--------+-----+---------+
| id | name   | age | info    |
+----+--------+-----+---------+
|  1 | Green  |  21 | student |
|  2 | Suse   |  22 | student |
|  4 | Willam |  20 | student |
|  7 | Dale   |  22 | student |
|  9 | Harry  |  21 | student |

可以看到,这些age字段值在19~22之间的记录存在表中。下面使用DELETE删除这些记录:

sql 复制代码
delete from person
where age between 19 and 22;

语句执行完毕,查看执行结果:

sql 复制代码
select * from person 
where age between 19 and 22;

+----+------+-----+------+
| id | name | age | info |
+----+------+-----+------+
+----+------+-----+------+

查询结果为空,删除多条记录成功。

删除person表中所有记录。

执行删除操作前,使用SELECT语句查看当前的数据:

sql 复制代码
select * from person;

+----+--------+-----+-----------+
| id | name   | age | info      |
+----+--------+-----+-----------+
|  3 | Mary   |  24 | Musician  |
|  5 | Laura  |  25 | <null>    |
|  6 | Evans  |  27 | secretary |
|  8 | Edison |  28 | singer    |
+----+--------+-----+-----------+

结果显示person表中还有4条记录,执行DELETE语句删除这4条记录:

sql 复制代码
delete from person;

语句执行完毕,查看执行结果:

sql 复制代码
select * from person;

+----+------+-----+------+
| id | name | age | info |
+----+------+-----+------+
+----+------+-----+------+

查询结果为空,说明删除表中所有记录成功,现在person表中已经没有任何数据记录。

如果想删除表中的所有记录,还可以使用TRUNCATE TABLE语句。TRUNCATE将直接删除原来的表,并重新创建一个表,其语法结构为TRUNCATE TABLE table_name。TRUNCATE直接删除表而不是删除记录,因此执行速度比DELETE快。

4、为表增加计算列

什么叫计算列呢?简单来说就是某一列的值是通过别的列计算得来的。例如,a列值为1、b列值为2,c列不需要手动插入,定义a+b的结果为c的值,那么c就是计算列,是通过别的列计算得来的。

增加计算列的语法格式如下:

sql 复制代码
col_name data_type [generated always] as (expression)
	[virtual | stored] [unique [key] [comment comment]
	[not null | null | [[primary] key]

在MySQL 8.0中,CREAE TABLE和ALTERTABLE中都支持增加计算列。下面以CREAETABLE为例进行讲解。

定义数据表tb1,然后定义字段id、字段a、字段b和字段c,其中字段c为计算列,用于计算a+b的值。

首先创建测试表tb1,语句如下:

sql 复制代码
create table tb1(
	id int(9) not null auto_increment,
	a int(9) default null,
	b int(9) default null,
	c int (9) generated always as ((a + b)) virtual,
	primary key (`id`)
);

插入演示数据,语句如下:

sql 复制代码
insert into tb1(a,b) values(100, 200);

查询数据表tb1中的数据,结果如下:

sql 复制代码
select * from tb1;

+----+-----+-----+-----+
| id |   a |   b |   c |
+----+-----+-----+-----+
|  1 | 100 | 200 | 300 |
+----+-----+-----+-----+

更新数据中的数据,语句如下:

sql 复制代码
update tb1 set a = 500;

再次查看数据表中的数据,结果如下:

sql 复制代码
select * from tb1;

+----+-----+-----+-----+
| id |   a |   b |   c |
+----+-----+-----+-----+
|  1 | 500 | 200 | 700 |
+----+-----+-----+-----+

从结果可以看出,字段c中的数据始终是字段a和字段b的和,随着字段a和字段b中数据的变化,自动重新计算a+b的值。

5、MySQL 8.0的新特性------DDL的原子化

在MySQL 8.0版本中,InnoDB表的DDL支持事务完整性,即DDL操作要么成功要么回滚。DDL操作回滚日志写入到datadictionary数据字典表mysql.innodb_ddl_log(该表是隐藏的表,通过show tables无法看到)中,用于回滚操作。通过设置参数,可将DDL操作日志打印输出到MySQL错误日志中。

下面通过案例来对比不同的版本中DDL操作的区别。

分别在MySQL 5.7版本和MySQL 8.0版本中创建数据库和数据表,结果如下:

sql 复制代码
create database my_test;
use my_test;

create table bk1
(
	bookid int not null,
	bookname varchar(255)
);

show tables;

+-------------------+
| Tables_in_my_test |
+-------------------+
| bk1               |
+-------------------+

在MySQL 5.7版本中,测试步骤如下:删除数据表bk1和数据表bk2,结果如下:

sql 复制代码
mysql> drop table bk1, bk2;
ERROR 1051 (42S02): Unknown table 'my_test.bk2'

再次查询数据库中的数据表名称,结果如下:

sql 复制代码
mysql> show tables;
Empty set (0.00 sec)

从结果可以看出,虽然删除操作时报错了,但是仍然删除了数据表bk1。

在MySQL 8.0版本中,测试步骤如下:删除数据表bk1和数据表bk2,结果如下:

sql 复制代码
mysql> drop table bk1, bk2;
ERROR 1051 (42S02): Unknown table 'my_test.bk2'

再次查询数据库中的数据表名称,结果如下:

sql 复制代码
show tables;

+-------------------+
| Tables_in_my_test |
+-------------------+
| bk1               |
+-------------------+

从结果可以看出,数据表bk1并没有被删除。