> 文章列表 > 【MySQL】(4)表的增删改查

【MySQL】(4)表的增删改查

【MySQL】(4)表的增删改查

文章目录

  • 表的增删改查
  • Create
    • INSERT
    • 插入重复时更新
    • 替换
  • Retrieve
    • SELECT
      • select执行顺序(重要)
      • 全列查询 指定列查询
      • 查询字段为表达式
    • where条件
    • 排序
    • 筛选分页结果
  • Update
  • Delete
    • delete
    • 截断表
  • 插入查询结果

表的增删改查

CRUD:Create(创建),Retrieve(读取),Update(更新),Delete(删除)

Create

INSERT

语法

INSERT [INTO] 表名 [(1,2,3, ...)]
VALUES (1,2,3, ...),(1,2,3, ...),(1,2,3, ...),... ;

INTO 可以省略

(列1, 列2, 列3, ...) 指定要插入的列,(值1, 值2, 值3, ...) 与指定的列一一对应

列名列表可以省略,如果省略,则等价于全列插入,下面插入数据时要按照顺序给所有列指定一个值或 null

插入重复时更新

由于主键或唯一键的存在,插入重复的值会导致插入失败

我们可以让插入改为更新操作。类似于 C++ unordered_mapoperator[],键不存在则插入新键值对,键存在则更新值。

语法

INSERT [INTO] 表名 [(1,2,3, ...)] VALUES (1,2,3, ...)
ON DUPLICATE KEY UPDATE1=新值1,2=新值2,3=新值3, ...;

其中,表名 是要插入数据的表名,列1, 列2, 列3, ... 是要插入数据的列名,值1, 值2, 值3, ... 是对应列的值。如果插入数据时出现了键冲突,即已有相同的主键或唯一键,则会执行 ON DUPLICATE KEY UPDATE 后面的语句来更新相应的数据。

向名为 students 的表中插入一条记录,包含学生的学号、姓名和年龄信息,如果已经存在相同的学号,则将更新对应的姓名和年龄信息:

INSERT INTO students (id, name, age)
VALUES (1001, '张三', 20)
ON DUPLICATE KEY UPDATE name='张三', age=20;

其中,id 列为主键,如果已存在学号为 1001 的记录,则会将该记录的 name 列和 age 列更新为 '张三'20。如果该学号不存在,则会插入一条新的记录,包含学号为 1001,姓名为 '张三',年龄为 20 的信息。

使用这个语句,可能会有三种返回结果:

  • 0 rows affected 表中有冲突数据,但更新的值与旧值相等
  • 1 row affected 表中没有冲突数据,数据插入
  • 2 rows affected 表中有冲突数据,数据更新

数据更新是两行受影响,这是因为更新数据分为两步,1.删除旧数据 2.插入新数据

替换

在 MySQL 中,替换数据可以使用 REPLACE 关键字。REPLACE 的作用是:如果表中存在指定的主键或唯一索引,则替换该行数据;如果不存在,则插入新的数据。

语法

REPLACE INTO 表名 (1,2,3, ...) VALUES (1,2,3, ...);

使用这个语句,可能会有以下返回结果:

  • 1 row affected 表中没有冲突数据,数据插入
  • 2 rows affected 表中有冲突数据,数据更新

注意

REPLACE 是删除冲突行后插入,有时候冲突行不止一个,比如有多个唯一键的情况,那么 MySQL 会将所有冲突的行都删除,最后插入一条新数据。

Retrieve

SELECT

SELECT 语句是 MySQL 中最常用的语句之一,用于从一个或多个表中查询数据。

语法

SELECT [DISTINCT] select_list
[FROM table_list]
[WHERE where_condition]
[GROUP BY grouping_columns]
[HAVING having_condition]
[ORDER BY ordering_columns [ASC|DESC], ...]
[LIMIT limit_number]
  • DISTINCT 是 MySQL 中用于去重的关键字,它可以用于查询中的 SELECT 语句,用于去除查询结果中重复的行。
  • select_list 是要查询的列的列表,用逗号分隔。可以使用通配符 * 来查询所有列。也可以在查询中使用函数和表达式来生成新的列。
  • table_list 是要查询的表的列表,用逗号分隔。可以使用子查询来查询多个表中的数据。
  • WHERE 子句用于指定查询条件,它可以包含一个或多个表达式,用逻辑运算符(如 AND、OR、NOT)组合。可以使用比较运算符(如 =、<、>、<=、>=、<>)和其他运算符(如 LIKE、IN、BETWEEN)来构建条件。
  • GROUP BY 子句用于将查询结果按照指定的列进行分组,通常与聚合函数一起使用。
  • HAVING 子句用于指定分组后的条件,通常用于对聚合函数的结果进行过滤。
  • ORDER BY 子句用于指定查询结果的排序顺序,可以按照一个或多个列进行排序,并可以指定每个列的排序方式(升序或降序)。
  • LIMIT 子句用于限制查询结果的行数,可以指定一个或两个参数。第一个参数指定要返回的行数,第二个参数指定从哪一行开始返回结果。

注意

使用多个可选项时要按照顺序写,比如 FROM 语句就是应该写在 WHERE 前面,不能写反

select执行顺序(重要)

在 SQL 中,SELECT 语句的执行顺序通常可以分为以下几个步骤:

  1. FROM 子句:从指定的表格中获取数据;
  2. JOIN 子句:如果使用了 JOIN 操作,则将多个表格中的数据进行关联;(涉及多表查询,后面讲)
  3. WHERE 子句:根据指定的条件过滤出符合要求的数据;
  4. GROUP BY 子句:按照指定的列对数据进行分组;
  5. HAVING 子句:对分组后的数据进行条件过滤;
  6. SELECT 子句:选择要显示的列;
  7. DISTINCT 子句:去除重复的数据;
  8. ORDER BY 子句:按照指定的列对数据进行排序;
  9. LIMIT 子句:限制查询结果的行数。

这里需要重点关注一下 selectdistinct 子句执行是在 having 之后,order by 之前,这和我们语句的书写顺序是不一致的。

全列查询 指定列查询

建表

CREATE TABLE student_scores (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(50) NOT NULL,chinese INT,math INT,english INT
);

插入数据

INSERT INTO student_scores (name, chinese, math, english) VALUES('Alice', 80, 85, 90),('Bob', 75, 80, 85),('Charlie', 90, 95, 85),('Dave', 85, 90, 90),('Emma', 95, 85, 90),('Frank', 70, 75, 80);

全列查询

MariaDB [test_db]> select * from student_scores;
+----+---------+---------+------+---------+
| id | name    | chinese | math | english |
+----+---------+---------+------+---------+
|  1 | Alice   |      80 |   85 |      90 |
|  2 | Bob     |      75 |   80 |      85 |
|  3 | Charlie |      90 |   95 |      85 |
|  4 | Dave    |      85 |   90 |      90 |
|  5 | Emma    |      95 |   85 |      90 |
|  6 | Frank   |      70 |   75 |      80 |
+----+---------+---------+------+---------+
6 rows in set (0.00 sec)

指定列查询

MariaDB [test_db]> select id, name from student_scores;
+----+---------+
| id | name    |
+----+---------+
|  1 | Alice   |
|  2 | Bob     |
|  3 | Charlie |
|  4 | Dave    |
|  5 | Emma    |
|  6 | Frank   |
+----+---------+
6 rows in set (0.00 sec)

查询字段为表达式

直接使用 select 计算表达式

MariaDB [test_db]> select 2*3+1;
+-------+
| 2*3+1 |
+-------+
|     7 |
+-------+
1 row in set (0.00 sec)

查询字段为字段表达式,如下,计算所有学生语文成绩+5分后的结果

MariaDB [test_db]> select id, name, chinese+5 from student_scores;
+----+---------+-----------+
| id | name    | chinese+5 |
+----+---------+-----------+
|  1 | Alice   |        85 |
|  2 | Bob     |        80 |
|  3 | Charlie |        95 |
|  4 | Dave    |        90 |
|  5 | Emma    |       100 |
|  6 | Frank   |        75 |
+----+---------+-----------+
6 rows in set (0.00 sec)

查询每个人的总分

MariaDB [test_db]> SELECT name, chinese + math + english AS total_score-> FROM student_scores;
+---------+-------------+
| name    | total_score |
+---------+-------------+
| Alice   |         255 |
| Bob     |         240 |
| Charlie |         270 |
| Dave    |         265 |
| Emma    |         270 |
| Frank   |         225 |
+---------+-------------+
6 rows in set (0.00 sec)

AS 是用来为查询结果中的列指定别名的关键字。需要注意的是,使用 AS 关键字是可选的。在 SQL 中,也可以不使用 AS 关键字为列指定别名,直接在查询语句中给列起一个名称。例如:

MariaDB [test_db]> SELECT name, chinese + math + english total_score-> FROM student_scores;

这条语句和上面是等价的。

where条件

比较运算符 说明
>>=<<= 大于,大于等于,小于,小于等于
= 等于,NULL 不安全,如 NULL = NULL 的结果是 NULL
<=> 等于,NULL 安全,如 NULL <=> NULL 的结果是 TRUE(1)
!=<> 不等于,NULL != NULLNULL <> NULL 的结果都是 NULL
BETWEEN a AND b 范围匹配,如果 a <= value <= b,则返回 TRUE(1)
IN(option, ...) 如果是 option 中的任意一个,返回 TRUE(1)
IS NULL NULL
IS NOT NULL 不是 NULL
LIKE 模糊匹配,% 表示任意多个任意字符,_ 表示任意一个字符
逻辑运算符 说明
AND 逻辑与
OR 逻辑或
NOT 逻辑非

在 SQL 中,NULL 表示缺失或未知的值,它不等于任何值,包括 NULL 本身。因此,NULL = NULL 的结果不是 TRUE,也不是 FALSE,而是 NULL

这是因为 NULL 值的比较无法确定两个值是否相等,因此比较的结果也是未知的。在 SQL 中,任何未知的结果都被认为是 NULL,因此 NULL=NULL 的结果也是 NULL

如果需要比较某个值是否为 NULL,可以使用 IS NULLIS NOT NULL 进行判断。

查询数学成绩大于等于90的记录

MariaDB [test_db]> select * from student_scores where math >= 90;
+----+---------+---------+------+---------+
| id | name    | chinese | math | english |
+----+---------+---------+------+---------+
|  3 | Charlie |      90 |   95 |      85 |
|  4 | Dave    |      85 |   90 |      90 |
+----+---------+---------+------+---------+
2 rows in set (0.00 sec)

向表中插入一行三科分数都为null的记录

MariaDB [test_db]> select * from student_scores;
+----+---------+---------+------+---------+
| id | name    | chinese | math | english |
+----+---------+---------+------+---------+
|  1 | Alice   |      80 |   85 |      90 |
|  2 | Bob     |      75 |   80 |      85 |
|  3 | Charlie |      90 |   95 |      85 |
|  4 | Dave    |      85 |   90 |      90 |
|  5 | Emma    |      95 |   85 |      90 |
|  6 | Frank   |      70 |   75 |      80 |
|  7 | God     |    NULL | NULL |    NULL |
+----+---------+---------+------+---------+
7 rows in set (0.00 sec)

使用 chinese=null 找不到这条记录,因为任何值与 null 比较都返回 null

需要用 is null

MariaDB [test_db]> select * from student_scores where chinese=null;
Empty set (0.00 sec)
MariaDB [test_db]> select * from student_scores where chinese is null;
+----+------+---------+------+---------+
| id | name | chinese | math | english |
+----+------+---------+------+---------+
|  7 | God  |    NULL | NULL |    NULL |
+----+------+---------+------+---------+
1 row in set (0.00 sec)

使用 between 选出数学成绩在80到90之间的信息

MariaDB [test_db]> select * from student_scores where math between 80 and 90;
+----+-------+---------+------+---------+
| id | name  | chinese | math | english |
+----+-------+---------+------+---------+
|  1 | Alice |      80 |   85 |      90 |
|  2 | Bob   |      75 |   80 |      85 |
|  4 | Dave  |      85 |   90 |      90 |
|  5 | Emma  |      95 |   85 |      90 |
+----+-------+---------+------+---------+
4 rows in set (0.00 sec)

使用 in() 判断

MariaDB [test_db]> select 1 in (1,2,3,4,5);
+------------------+
| 1 in (1,2,3,4,5) |
+------------------+
|                1 |
+------------------+
1 row in set (0.00 sec)MariaDB [test_db]> select -1 in (1,2,3,4,5);
+-------------------+
| -1 in (1,2,3,4,5) |
+-------------------+
|                 0 |
+-------------------+
1 row in set (0.00 sec)

查询语文成绩为75或95的记录

MariaDB [test_db]> select * from student_scores where chinese in (75,95);
+----+------+---------+------+---------+
| id | name | chinese | math | english |
+----+------+---------+------+---------+
|  2 | Bob  |      75 |   80 |      85 |
|  5 | Emma |      95 |   85 |      90 |
+----+------+---------+------+---------+
2 rows in set (0.00 sec)

也可以使用 OR 来连接多个判断语句

select * from student_scores where chinese=75 OR chinese=95;

这两个SQL语句是等价的。


使用模糊匹配查询名字里有字母a的记录

MariaDB [test_db]> select * from student_scores where name like '%a%';
+----+---------+---------+------+---------+
| id | name    | chinese | math | english |
+----+---------+---------+------+---------+
|  1 | Alice   |      80 |   85 |      90 |
|  3 | Charlie |      90 |   95 |      85 |
|  4 | Dave    |      85 |   90 |      90 |
|  5 | Emma    |      95 |   85 |      90 |
|  6 | Frank   |      70 |   75 |      80 |
+----+---------+---------+------+---------+
5 rows in set (0.00 sec)

找出总分小于260的学生信息

MariaDB [test_db]> select id, name, chinese+math+english as total from student_scores where chinese+math+english < 260;
+----+-------+-------+
| id | name  | total |
+----+-------+-------+
|  1 | Alice |   255 |
|  2 | Bob   |   240 |
|  6 | Frank |   225 |
+----+-------+-------+
3 rows in set (0.00 sec)

有些人可能会这样写:

MariaDB [test_db]> select id, name, chinese+math+english as total from student_scores where total < 260;
ERROR 1054 (42S22): Unknown column 'total' in 'where clause'

这就是一个经典的错误,标准的零分。因为取别名的执行顺序在 where 语句之后,where 里面就开始写别名 MySQL 是不认识的。


查询名字里没有字母e,并且语文成绩大于70的同学

MariaDB [test_db]> select * from student_scores where name not like '%e%' and chinese > 70;
+----+------+---------+------+---------+
| id | name | chinese | math | english |
+----+------+---------+------+---------+
|  2 | Bob  |      75 |   80 |      85 |
+----+------+---------+------+---------+
1 row in set (0.00 sec)

排序

按数学成绩升序排序

MariaDB [test_db]> select name, math from student_scores order by math;
+---------+------+
| name    | math |
+---------+------+
| God     | NULL |
| Frank   |   75 |
| Bob     |   80 |
| Alice   |   85 |
| Emma    |   85 |
| Dave    |   90 |
| Charlie |   95 |
+---------+------+
7 rows in set (0.00 sec)

默认排序方式就是升序排序。

按数学成绩降序排序

MariaDB [test_db]> select name, math from student_scores order by math desc;
+---------+------+
| name    | math |
+---------+------+
| Charlie |   95 |
| Dave    |   90 |
| Alice   |   85 |
| Emma    |   85 |
| Bob     |   80 |
| Frank   |   75 |
| God     | NULL |
+---------+------+
7 rows in set (0.01 sec)

指定排序方式 desc 即为降序排序

NULL 被视为最小值

按数学降序,英语升序,语文升序方式排序

MariaDB [test_db]> select * from student_scores order by math desc, english asc, chinese asc;
+----+---------+---------+------+---------+
| id | name    | chinese | math | english |
+----+---------+---------+------+---------+
|  3 | Charlie |      90 |   95 |      85 |
|  4 | Dave    |      85 |   90 |      90 |
|  1 | Alice   |      80 |   85 |      90 |
|  5 | Emma    |      95 |   85 |      90 |
|  2 | Bob     |      75 |   80 |      85 |
|  6 | Frank   |      70 |   75 |      80 |
|  7 | God     |    NULL | NULL |    NULL |
+----+---------+---------+------+---------+
7 rows in set (0.00 sec)

多字段排序,各 字段 排序方式 之间用 , 分隔

按总分升序排序

MariaDB [test_db]> select id, name, chinese+math+english as total from student_scores order by total;
+----+---------+-------+
| id | name    | total |
+----+---------+-------+
|  7 | God     |  NULL |
|  6 | Frank   |   225 |
|  2 | Bob     |   240 |
|  1 | Alice   |   255 |
|  4 | Dave    |   265 |
|  3 | Charlie |   270 |
|  5 | Emma    |   270 |
+----+---------+-------+
7 rows in set (0.00 sec)

这里我们在 order by 里面使用别名就不会报错,原因是 select 选择显示列的执行在 order by 排序之前。

筛选分页结果

语法

LIMIT [offset,] rows_count;LIMIT rows_count OFFSET offset;

其中,rows_count 表示要返回的行数,offset 表示从查询结果的哪一行开始返回(从 0 开始)。可以省略 offset 参数,此时默认从第一行开始返回,例如:

  • LIMIT 10:返回前 10 行数据;
  • LIMIT 5, 10:从第 6 行开始返回,返回 10 行数据。
    • 也可以写成 LIMIT 10 OFFSET 5 这两种写法是等价的

查询总分排名前三的

MariaDB [test_db]> select id, name, chinese+math+english as total from student_scores order by total desc limit 3;
+----+---------+-------+
| id | name    | total |
+----+---------+-------+
|  3 | Charlie |   270 |
|  5 | Emma    |   270 |
|  4 | Dave    |   265 |
+----+---------+-------+
3 rows in set (0.00 sec)

查询总分排名第四到第六的

MariaDB [test_db]> select id, name, chinese+math+english as total from student_scores order by total desc limit 3, 3;
+----+-------+-------+
| id | name  | total |
+----+-------+-------+
|  1 | Alice |   255 |
|  2 | Bob   |   240 |
|  6 | Frank |   225 |
+----+-------+-------+
3 rows in set (0.00 sec)

Update

语法

UPDATE table_name
SET column1 = value1, column2 = value2, ...
[WHERE where_condition]
[ORDER BY ordering_columns [ASC|DESC], ...]
[LIMIT limit_number];

注意

where 子句基本上是必写的,如果不写,所有记录都会被修改。

将id为4的同学的语文成绩改为 80,英语成绩改为 95

SQL 语句如下:

update student_scores
set chinese=80,english=95
where id=4;

结果:

MariaDB [test_db]> update student_scores set chinese=80,english=95 where id=4;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0MariaDB [test_db]> select * from student_scores;
+----+---------+---------+------+---------+
| id | name    | chinese | math | english |
+----+---------+---------+------+---------+
|  1 | Alice   |      80 |   85 |      90 |
|  2 | Bob     |      75 |   80 |      85 |
|  3 | Charlie |      90 |   95 |      85 |
|  4 | Dave    |      80 |   90 |      95 |
|  5 | Emma    |      95 |   85 |      90 |
|  6 | Frank   |      70 |   75 |      80 |
|  7 | God     |    NULL | NULL |    NULL |
+----+---------+---------+------+---------+
7 rows in set (0.00 sec)

将数学成绩倒数前三的同学的数学成绩+3分

update student_scores
set math=math+3
order by math
limit 3;

结果:

MariaDB [test_db]> select * from student_scores;
+----+---------+---------+------+---------+
| id | name    | chinese | math | english |
+----+---------+---------+------+---------+
|  1 | Alice   |      80 |   85 |      90 |
|  2 | Bob     |      75 |   83 |      85 |
|  3 | Charlie |      90 |   95 |      85 |
|  4 | Dave    |      80 |   90 |      95 |
|  5 | Emma    |      95 |   85 |      90 |
|  6 | Frank   |      70 |   78 |      80 |
|  7 | God     |    NULL | NULL |    NULL |
+----+---------+---------+------+---------+
7 rows in set (0.00 sec)

Frank 和 Bob 的数学成绩加了 3 分,God 没有成绩,但 null 被视为最小值,成绩+3 还是 null。

Delete

delete

语法

DELETE FROM table_name
[WHERE where_condition]
[ORDER BY ordering_columns [ASC|DESC], ...]
[LIMIT limit_number];

删除 id 为 2 的学生记录

MariaDB [test_db]> delete from student_scores where id=2;
Query OK, 1 row affected (0.01 sec)MariaDB [test_db]> select * from student_scores;
+----+---------+---------+------+---------+
| id | name    | chinese | math | english |
+----+---------+---------+------+---------+
|  1 | Alice   |      80 |   85 |      90 |
|  3 | Charlie |      90 |   95 |      85 |
|  4 | Dave    |      80 |   90 |      95 |
|  5 | Emma    |      95 |   85 |      90 |
|  6 | Frank   |      70 |   78 |      80 |
|  7 | God     |    NULL | NULL |    NULL |
+----+---------+---------+------+---------+
6 rows in set (0.00 sec)

如果你想删除所有数据,可以不加 where 条件。

需要注意的是,DELETE 语句删除的数据不可恢复,因此在执行删除操作之前,一定要仔细确认。

截断表

截断表(TRUNCATE TABLE)是一种删除表中所有数据的快速方法。与 DELETE FROM 语句相比,使用 TRUNCATE TABLE 可以更快地清空表中的数据,并且不需要记录日志,因此它的执行速度更快。

语法

TRUNCATE [TABLE] table_name;

插入查询结果

插入查询结果是指将一个 SELECT 查询的结果插入到另一个表中,也称为“插入选择”(INSERT INTO ... SELECT)。

语法

INSERT INTO table_name [(column1, column2, column3, ...)]
SELECT column1, column2, column3, ...
FROM another_table
WHERE ...

其中,table_name 是要插入数据的目标表的名称,括号中的列名指定了要插入的列,可以省略。SELECT 查询语句用于查询要插入的数据,可以根据需要添加 WHERE 子句来筛选数据。查询结果中的列与目标表中的列一一对应,如果目标表中的列少于查询结果中的列,只会插入目标表中的列对应的数据。

需要注意的是,插入查询结果时,目标表的结构必须与查询结果的列数和数据类型一致,否则会发生插入失败或数据截断等错误。同时,插入查询结果时,如果目标表中已经存在与查询结果中的数据主键或唯一键冲突的行,将会插入失败。

创建一个与 student_scores 结构相同的表

MariaDB [test_db]> create table student_scores_backup like student_scores;
Query OK, 0 rows affected (0.01 sec)

使用插入查询语句将 student_scores 表的数据插入到新表 student_scores_backup

MariaDB [test_db]> insert into student_scores_backup-> select * from student_scores;
Query OK, 6 rows affected (0.00 sec)
Records: 6  Duplicates: 0  Warnings: 0MariaDB [test_db]> select * from student_scores_backup;
+----+---------+---------+------+---------+
| id | name    | chinese | math | english |
+----+---------+---------+------+---------+
|  1 | Alice   |      80 |   85 |      90 |
|  3 | Charlie |      90 |   95 |      85 |
|  4 | Dave    |      80 |   90 |      95 |
|  5 | Emma    |      95 |   85 |      90 |
|  6 | Frank   |      70 |   78 |      80 |
|  7 | God     |    NULL | NULL |    NULL |
+----+---------+---------+------+---------+
6 rows in set (0.00 sec)

这样就完成了一个表的备份。