CRUD:Create(创建),Retrieve(读取),Update(更新),Delete(删除)
语法:
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_map
的 operator[]
,键不存在则插入新键值对,键存在则更新值。
语法:
INSERT [INTO] 表名 [(列1, 列2, 列3, ...)] VALUES (值1, 值2, 值3, ...)
ON DUPLICATE KEY UPDATE 列1=新值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 会将所有冲突的行都删除,最后插入一条新数据。
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
前面,不能写反
在 SQL 中,SELECT
语句的执行顺序通常可以分为以下几个步骤:
FROM
子句:从指定的表格中获取数据;JOIN
子句:如果使用了 JOIN
操作,则将多个表格中的数据进行关联;(涉及多表查询,后面讲)WHERE
子句:根据指定的条件过滤出符合要求的数据;GROUP BY
子句:按照指定的列对数据进行分组;HAVING
子句:对分组后的数据进行条件过滤;SELECT
子句:选择要显示的列;DISTINCT
子句:去除重复的数据;ORDER BY
子句:按照指定的列对数据进行排序;LIMIT
子句:限制查询结果的行数。这里需要重点关注一下 select
和 distinct
子句执行是在 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;
这条语句和上面是等价的。
比较运算符 | 说明 |
---|---|
> ,>= ,< ,<= |
大于,大于等于,小于,小于等于 |
= |
等于,NULL 不安全,如 NULL = NULL 的结果是 NULL |
<=> |
等于,NULL 安全,如 NULL <=> NULL 的结果是 TRUE(1) |
!= ,<> |
不等于,NULL != NULL 和 NULL <> 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 NULL
或 IS 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 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: 0
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 | 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 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: 0
MariaDB [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)
这样就完成了一个表的备份。