本篇将主要介绍在MySql中的表的增删查改(CURD)操作,还会介绍关于MySql中的聚合函数,排序以及分组。
文章目录
insert插入
向表中插入数据,语法如下:
mysql
INSERT [INTO] table_name
[(column [, column] ...)]
VALUES (value_list) [, (value_list)] ...
value_list: value, [, value] ...
创建一个示例表:
mysql
mysql> create table students (
-> id int unsigned primary key auto_increment,
-> sn int not null unique comment '学号',
-> name varchar(20) not null,
-> qq varchar(20)
-> );
Query OK, 0 rows affected (0.02 sec)
单行数据全列插入
在进行单行数据全列插入的时候,value_list必须和定义表的列的数量以及顺序一致,如下:
mysql
mysql> insert into students values (100, 10000, '猪八戒', null);
Query OK, 1 row affected (0.01 sec)
mysql> insert into students values (101, 10001, '孙悟空', '11111');
Query OK, 1 row affected (0.00 sec)
mysql> select * from students;
+-----+-------+-----------+-------+
| id | sn | name | qq |
+-----+-------+-----------+-------+
| 100 | 10000 | 猪八戒 | NULL |
| 101 | 10001 | 孙悟空 | 11111 |
+-----+-------+-----------+-------+
2 rows in set (0.00 sec)
多行数据指定列插入
如下所示,我们将一次插入多行数据,并且是指定列插入:
mysql
mysql> insert into students (id, name, sn) values
-> (102, '沙和尚', 10002),
-> (103, '白龙马', 10003);
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> select * from students;
+-----+-------+-----------+-------+
| id | sn | name | qq |
+-----+-------+-----------+-------+
| 100 | 10000 | 猪八戒 | NULL |
| 101 | 10001 | 孙悟空 | 11111 |
| 102 | 10002 | 沙和尚 | NULL |
| 103 | 10003 | 白龙马 | NULL |
+-----+-------+-----------+-------+
插入否则更新
当我们插入数据由于主键或者唯一键对应的值存在而插入失败的时候,我们可以使用更新策略,语法如下:
mysql
INSERT ... ON DUPLICATE KEY UPDATE
column = value [, column = value] ...
示例如下:
mysql
mysql> insert into students (id, sn, name) values (100, 10010, '唐三藏');
ERROR 1062 (23000): Duplicate entry '100' for key 'PRIMARY'
mysql> insert into students (sn, name) values (10000, '曹孟德');
ERROR 1062 (23000): Duplicate entry '10000' for key 'sn'
mysql> INSERT INTO students (id, sn, name) VALUES (100, 10010, '唐大师')
-> ON DUPLICATE KEY UPDATE sn = 10010, name = '唐大师';
Query OK, 2 rows affected (0.00 sec)
-- 0 row affected: 表中存在冲突数据,但冲突数据的值和update的值相等
-- 1 row affected: 表中没有冲突数据,数据被插入
-- 2 row affected: 表中有冲突数据,并且数据已经被更新
mysql> select * from students;
+-----+-------+-----------+-------+
| id | sn | name | qq |
+-----+-------+-----------+-------+
| 100 | 10010 | 唐大师 | NULL |
| 101 | 10001 | 孙悟空 | 11111 |
| 102 | 10002 | 沙和尚 | NULL |
| 103 | 10003 | 白龙马 | NULL |
+-----+-------+-----------+-------+
4 rows in set (0.00 sec)
当我们使用插入否则更新语法的时候,我们可以通过被影响行数来判断表中是否存在数据冲突,以及冲突的值是否和需要插入的值相等。同时我们还可以使用 row_count() 函数来获取当前受到影响的数据行数,如下:
mysql
mysql> select row_count();
+-------------+
| row_count() |
+-------------+
| 2 |
+-------------+
1 row in set (0.00 sec)
替换
对于替换操作,就是替换表中的某个数据,若要替换的数据和表中的数据没有冲突,则直接插入,若有冲突,则删除之后再插入
mysql
mysql> replace into students (sn, name) values (10001, '唐国公');
Query OK, 2 rows affected (0.00 sec)
mysql> replace into students (sn, name) values (10008, '豹子头');
Query OK, 1 row affected (0.00 sec)
mysql> select * from students;
+-----+-------+-----------+------+
| id | sn | name | qq |
+-----+-------+-----------+------+
| 100 | 10010 | 唐三藏 | NULL |
| 102 | 10002 | 沙和尚 | NULL |
| 103 | 10003 | 白龙马 | NULL |
| 105 | 10001 | 唐国公 | NULL |
| 106 | 10008 | 豹子头 | NULL |
+-----+-------+-----------+------+
5 rows in set (0.00 sec)
select/Retrieve查询
对于查询的语法如下:
mysql
SELECT
[DISTINCT] {* | {column [, column] ...}
[FROM table_name]
[WHERE ...]
[ORDER BY column [ASC | DESC], ...]
LIMIT ...
先把需要用来测试的用力创建表格以及插入数据,如下:
mysql
mysql> CREATE TABLE exam_result (
-> id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
-> name VARCHAR(20) NOT NULL COMMENT '同学姓名',
-> chinese float DEFAULT 0.0 COMMENT '语文成绩',
-> math float DEFAULT 0.0 COMMENT '数学成绩',
-> english float DEFAULT 0.0 COMMENT '英语成绩'
-> );
Query OK, 0 rows affected (0.02 sec)
mysql> INSERT INTO exam_result (name, chinese, math, english) VALUES
-> ('唐三藏', 67, 98, 56),
-> ('孙悟空', 87, 78, 77),
-> ('猪悟能', 88, 98, 90),
-> ('曹孟德', 82, 84, 67),
-> ('刘玄德', 55, 85, 45),
-> ('孙权', 70, 73, 78),
-> ('宋公明', 75, 65, 30);
Query OK, 7 rows affected (0.00 sec)
Records: 7 Duplicates: 0 Warnings: 0
select列
全列查询
全列查询就是直接查看所有的数据,通常不建议使用全列查询。因为:
-
查询的列越多,意味着需要传输的数据量越大;
-
可能会影响到索引的使用。
如下为全列查询:
mysql
mysql> select * from exam_result;
+----+-----------+---------+------+---------+
| id | name | chinese | math | english |
+----+-----------+---------+------+---------+
| 1 | 唐三藏 | 67 | 98 | 56 |
| 2 | 孙悟空 | 87 | 78 | 77 |
| 3 | 猪悟能 | 88 | 98 | 90 |
| 4 | 曹孟德 | 82 | 84 | 67 |
| 5 | 刘玄德 | 55 | 85 | 45 |
| 6 | 孙权 | 70 | 73 | 78 |
| 7 | 宋公明 | 75 | 65 | 30 |
+----+-----------+---------+------+---------+
7 rows in set (0.00 sec)
指定列查询
指定列查询不需要按定义表的顺序来,如下:
mysql
mysql> select id, name, english from exam_result;
+----+-----------+---------+
| id | name | english |
+----+-----------+---------+
| 1 | 唐三藏 | 56 |
| 2 | 孙悟空 | 77 |
| 3 | 猪悟能 | 90 |
| 4 | 曹孟德 | 67 |
| 5 | 刘玄德 | 45 |
| 6 | 孙权 | 78 |
| 7 | 宋公明 | 30 |
+----+-----------+---------+
7 rows in set (0.00 sec)
查询字段为表达式
表达式不包含字段,如下:
mysql
mysql> select id, name, 1 + 1 from exam_result;
+----+-----------+-------+
| id | name | 1 + 1 |
+----+-----------+-------+
| 1 | 唐三藏 | 2 |
| 2 | 孙悟空 | 2 |
| 3 | 猪悟能 | 2 |
| 4 | 曹孟德 | 2 |
| 5 | 刘玄德 | 2 |
| 6 | 孙权 | 2 |
| 7 | 宋公明 | 2 |
+----+-----------+-------+
7 rows in set (0.00 sec)
表达式包含一个字段,如下:
mysql
mysql> select id, name, 20 + math from exam_result;
+----+-----------+-----------+
| id | name | 20 + math |
+----+-----------+-----------+
| 1 | 唐三藏 | 118 |
| 2 | 孙悟空 | 98 |
| 3 | 猪悟能 | 118 |
| 4 | 曹孟德 | 104 |
| 5 | 刘玄德 | 105 |
| 6 | 孙权 | 93 |
| 7 | 宋公明 | 85 |
+----+-----------+-----------+
7 rows in set (0.00 sec)
表达式包含多个字段,如下:
mysql
mysql> select id, name, english + math + chinese from exam_result;
+----+-----------+--------------------------+
| id | name | english + math + chinese |
+----+-----------+--------------------------+
| 1 | 唐三藏 | 221 |
| 2 | 孙悟空 | 242 |
| 3 | 猪悟能 | 276 |
| 4 | 曹孟德 | 233 |
| 5 | 刘玄德 | 185 |
| 6 | 孙权 | 221 |
| 7 | 宋公明 | 170 |
+----+-----------+--------------------------+
7 rows in set (0.00 sec)
为查询结果指定别名
语法:
mysql
SELECT column [AS] alias_name [...] FROM table_name;
如下示例:
mysql
mysql> select id, name, english + math + chinese 总分 from exam_result;
+----+-----------+--------+
| id | name | 总分 |
+----+-----------+--------+
| 1 | 唐三藏 | 221 |
| 2 | 孙悟空 | 242 |
| 3 | 猪悟能 | 276 |
| 4 | 曹孟德 | 233 |
| 5 | 刘玄德 | 185 |
| 6 | 孙权 | 221 |
| 7 | 宋公明 | 170 |
+----+-----------+--------+
7 rows in set (0.00 sec)
查询结果去重
对查询结果去重,使用distinct关键字,如下:
mysql
mysql> select math from exam_result;
+------+
| math |
+------+
| 98 |
| 78 |
| 98 |
| 84 |
| 85 |
| 73 |
| 65 |
+------+
7 rows in set (0.00 sec)
mysql> select distinct math from exam_result;
+------+
| math |
+------+
| 98 |
| 78 |
| 84 |
| 85 |
| 73 |
| 65 |
+------+
6 rows in set (0.00 sec)
where条件查询
使用where在select进行查找,其实就是在表中使用条件进行筛选,所以会有着各种的运算符。
比较运算符:
运算符 | 说明 |
---|---|
>,>=,<,<= | 大于、大于等于、小于、小于等于 |
= | 等于,NULL不安全,例如NULL=NULL的结果是NULL |
<=> | 等于,NULL安全,NULL<=>NULL的结果是true |
!=, <> | 不等于 |
BETWEEN a0 AND a1 | 范围匹配,[a0, a1],如果 a0 <= value <= a1,返回 TRUE(1) |
IN (option, ...) | 如果是 option 中的任意一个,返回 TRUE(1) |
IS NULL | 是 NULL |
IS NOT NULL | 不是 NULL |
LIKE | 模糊匹配,%表示任意多个(包括0个)任意字符;_表示一个字符 |
逻辑运算符:
运算符 | 说明 |
---|---|
AND | 每个条件都为true(1),结果才是true(1) |
OR | 任意一个条件为true(1),结果为true(1) |
NOT | 条件为true(1),结果为false(0) |
比较运算查询
如下查询英语成绩不合格的同学以及语文成绩大于英语成绩的同学:
mysql
mysql> select name, english from exam_result where english < 60;
+-----------+---------+
| name | english |
+-----------+---------+
| 唐三藏 | 56 |
| 刘玄德 | 45 |
| 宋公明 | 30 |
+-----------+---------+
3 rows in set (0.00 sec)
mysql> select name, chinese, english from exam_result where chinese > english;
+-----------+---------+---------+
| name | chinese | english |
+-----------+---------+---------+
| 唐三藏 | 67 | 56 |
| 孙悟空 | 87 | 77 |
| 曹孟德 | 82 | 67 |
| 刘玄德 | 55 | 45 |
| 宋公明 | 75 | 30 |
+-----------+---------+---------+
5 rows in set (0.00 sec)
查询总分在200分以下的同学,如下:
mysql
mysql> select name, chinese + math + english 总分 from exam_result where chinese + math + english < 200;
+-----------+--------+
| name | 总分 |
+-----------+--------+
| 刘玄德 | 185 |
| 宋公明 | 170 |
+-----------+--------+
2 rows in set (0.00 sec)
区间查询
区间查询既可以使用AND进行区间查询,也可以使用BETWEEN AND进行区间查询,如下:
mysql
mysql> select name, chinese from exam_result where chinese >= 80 and chinese <= 90;
+-----------+---------+
| name | chinese |
+-----------+---------+
| 孙悟空 | 87 |
| 猪悟能 | 88 |
| 曹孟德 | 82 |
+-----------+---------+
3 rows in set (0.00 sec)
mysql> select name, chinese from exam_result where chinese between 80 and 90;
+-----------+---------+
| name | chinese |
+-----------+---------+
| 孙悟空 | 87 |
| 猪悟能 | 88 |
| 曹孟德 | 82 |
+-----------+---------+
3 rows in set (0.00 sec)
特定值查询
可以使用OR或者IN对某些特定值进行查询,如下:
mysql
mysql> select name, math from exam_result where math = 58
-> or math = 59 or math = 98 or math = 99;
+-----------+------+
| name | math |
+-----------+------+
| 唐三藏 | 98 |
| 猪悟能 | 98 |
+-----------+------+
2 rows in set (0.00 sec)
mysql> select name, math from exam_result where math in (58, 59, 98, 99);
+-----------+------+
| name | math |
+-----------+------+
| 唐三藏 | 98 |
| 猪悟能 | 98 |
+-----------+------+
2 rows in set (0.00 sec)
模糊查询
使用like进行模糊匹配查询,当在需要查询的关键字后面加上%的时候表示匹配0个或者多个字符,关键字后面加上几个_表示匹配几个字符,如下:
mysql
mysql> select name from exam_result where name like '孙%';
+-----------+
| name |
+-----------+
| 孙悟空 |
| 孙权 |
+-----------+
2 rows in set (0.00 sec)
mysql> select name from exam_result where name like '孙_';
+--------+
| name |
+--------+
| 孙权 |
+--------+
1 row in set (0.00 sec)
NOT查询
查询语文成绩大于80且不幸孙的同学,如下:
mysql
mysql> select name, chinese from exam_result where chinese > 80 and name not like '孙%';
+-----------+---------+
| name | chinese |
+-----------+---------+
| 猪悟能 | 88 |
| 曹孟德 | 82 |
+-----------+---------+
2 rows in set (0.00 sec)
综合性查询
查询姓孙的同学,总成绩大于200,语文成绩小于数学成绩并且英语成绩大于80,如下:
mysql
mysql> select name, math, english, chinese, math + english + chinese 总分 from exam_result
-> where name like '孙%' or (chinese + math + english > 200 and chinese < math and english > 80);
+-----------+------+---------+---------+--------+
| name | math | english | chinese | 总分 |
+-----------+------+---------+---------+--------+
| 孙悟空 | 78 | 77 | 87 | 242 |
| 猪悟能 | 98 | 90 | 88 | 276 |
| 孙权 | 73 | 78 | 70 | 221 |
+-----------+------+---------+---------+--------+
3 rows in set (0.01 sec)
NULL查询
查询表中的null值以及表中不为null的值,如下:
mysql
mysql> desc students;
+-------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| sn | int(11) | NO | UNI | NULL | |
| name | varchar(20) | NO | | NULL | |
| qq | varchar(20) | YES | | NULL | |
+-------+------------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)
mysql> select * from students where qq<=>null;
+-----+-------+-----------+------+
| id | sn | name | qq |
+-----+-------+-----------+------+
| 100 | 10010 | 唐三藏 | NULL |
| 102 | 10002 | 沙和尚 | NULL |
| 103 | 10003 | 白龙马 | NULL |
| 105 | 10001 | 唐国公 | NULL |
| 106 | 10008 | 豹子头 | NULL |
+-----+-------+-----------+------+
5 rows in set (0.00 sec)
mysql> select name, qq from students where qq is not null;
+-----------+------+
| name | qq |
+-----------+------+
| 林黛玉 | 220 |
+-----------+------+
1 row in set (0.00 sec)
ORDER BY查询
使用order by对数据进行筛查的时候,可以将数据按照某种条件进行排序,语法如下:
mysql
-- ASC 为升序(从小到大)
-- DESC 为降序(从大到小)
-- 默认为 ASC
SELECT ... FROM table_name [WHERE ...]
ORDER BY column [ASC|DESC], [...];
注:没有order by子句的查询,返回的顺序是未定义的,永远不要以来这个顺序。
升序排序
升序排序(默认是升序排序,若是降序排序需要指定):
mysql
mysql> select name, math from exam_result order by math;
+-----------+------+
| name | math |
+-----------+------+
| 宋公明 | 65 |
| 孙权 | 73 |
| 孙悟空 | 78 |
| 曹孟德 | 84 |
| 刘玄德 | 85 |
| 唐三藏 | 98 |
| 猪悟能 | 98 |
+-----------+------+
7 rows in set (0.00 sec)
mysql> select name, qq from students order by qq;
+-----------+------+
| name | qq |
+-----------+------+
| 唐三藏 | NULL |
| 沙和尚 | NULL |
| 白龙马 | NULL |
| 唐国公 | NULL |
| 豹子头 | NULL |
| 林黛玉 | 220 |
+-----------+------+
6 rows in set (0.01 sec)
null默认情况比任何值都小。
降序排序
降序排序需要在指定desc,如下:
mysql
mysql> select name, qq from students order by qq desc;
+-----------+------+
| name | qq |
+-----------+------+
| 林黛玉 | 220 |
| 唐三藏 | NULL |
| 沙和尚 | NULL |
| 白龙马 | NULL |
| 唐国公 | NULL |
| 豹子头 | NULL |
+-----------+------+
6 rows in set (0.00 sec)
mysql> select name, chinese + math + english from exam_result order by chinese + math + english desc;
+-----------+--------------------------+
| name | chinese + math + english |
+-----------+--------------------------+
| 猪悟能 | 276 |
| 孙悟空 | 242 |
| 曹孟德 | 233 |
| 唐三藏 | 221 |
| 孙权 | 221 |
| 刘玄德 | 185 |
| 宋公明 | 170 |
+-----------+--------------------------+
7 rows in set (0.00 sec)
--order by子句可以使用别名
mysql> SELECT name, chinese + english + math 总分 FROM exam_result
-> ORDER BY 总分 DESC;
+-----------+--------+
| name | 总分 |
+-----------+--------+
| 猪悟能 | 276 |
| 孙悟空 | 242 |
| 曹孟德 | 233 |
| 唐三藏 | 221 |
| 孙权 | 221 |
| 刘玄德 | 185 |
| 宋公明 | 170 |
+-----------+--------+
7 rows in set (0.00 sec)
在我们使用where子句的时候不可以直接使用别名,但是在使用order by子句的时候却可以使用别名,这涉及sql语句执行的顺序:
sql语句需要先找到数据在哪个表,也就是先找到from关键字后面的tablename
然后查看是否存在where关键,通过where子句筛选出需要操作的数据
然后在到select关键字后面去看要查询哪些数据
对于order by而言,前提就是需要存在数据然后排序,所以order by是等到所有数据都找到之后才排序,然后在排序前,别名所带有的数据已经被找到。
所以对于是否能使用别名的主要原因是,sql语句在使用别名的时候,别名是否已经定义(已经带有数据)。
综合查询
查询同学成绩,按照数学降序,英语升序,语文升序的方式,如下:
mysql
mysql> select name, math, english, chinese from exam_result order by math desc,
-> english asc, chinese asc;
+-----------+------+---------+---------+
| name | math | english | chinese |
+-----------+------+---------+---------+
| 唐三藏 | 98 | 56 | 67 |
| 猪悟能 | 98 | 90 | 88 |
| 刘玄德 | 85 | 45 | 55 |
| 曹孟德 | 84 | 67 | 82 |
| 孙悟空 | 78 | 77 | 87 |
| 孙权 | 73 | 78 | 70 |
| 宋公明 | 65 | 30 | 75 |
+-----------+------+---------+---------+
7 rows in set (0.00 sec)
多字段排序,优先级随书写顺序。
查询姓孙的同学或者姓曹的同学数学成绩,结果按数学成绩由高到低显示,如下结合where和order by:
mysql
mysql> select name, math from exam_result
-> where name like '孙%' or name like '曹%'
-> order by math desc;
+-----------+------+
| name | math |
+-----------+------+
| 曹孟德 | 84 |
| 孙悟空 | 78 |
| 孙权 | 73 |
+-----------+------+
3 rows in set (0.00 sec)
筛选分页结果
筛选分页的作用就是限制找到数据的行数,筛选分页的语法如下:
mysql
-- 起始下标为 0
-- 从 s 开始,筛选 n 条结果
SELECT ... FROM table_name [WHERE ...] [ORDER BY ...] LIMIT s, n
-- 从 0 开始,筛选 n 条结果
SELECT ... FROM table_name [WHERE ...] [ORDER BY ...] LIMIT n;
-- 从 s 开始,筛选 n 条结果,比第二种用法更明确,建议使用
SELECT ... FROM table_name [WHERE ...] [ORDER BY ...] LIMIT n OFFSET s;
以上的LIMIT表示最多查询多少条,另外,对于位置表进行查询的时候,最好加一条LIMIT 1,避免因为表中的数据量过大,查询全表可能会大致数据库卡死。
按id进行分页,每页3条记录,分别显示1、2、3页,如下:
mysql
mysql> SELECT id, name, math, english, chinese FROM exam_result
-> ORDER BY id LIMIT 3 OFFSET 0;
+----+-----------+------+---------+---------+
| id | name | math | english | chinese |
+----+-----------+------+---------+---------+
| 1 | 唐三藏 | 98 | 56 | 67 |
| 2 | 孙悟空 | 78 | 77 | 87 |
| 3 | 猪悟能 | 98 | 90 | 88 |
+----+-----------+------+---------+---------+
3 rows in set (0.00 sec)
mysql> SELECT id, name, math, english, chinese FROM exam_result ORDER BY id LIMIT 3 OFFSET 3;
+----+-----------+------+---------+---------+
| id | name | math | english | chinese |
+----+-----------+------+---------+---------+
| 4 | 曹孟德 | 84 | 67 | 82 |
| 5 | 刘玄德 | 85 | 45 | 55 |
| 6 | 孙权 | 73 | 78 | 70 |
+----+-----------+------+---------+---------+
3 rows in set (0.00 sec)
mysql> SELECT id, name, math, english, chinese FROM exam_result ORDER BY id LIMIT 3 OFFSET 6;
+----+-----------+------+---------+---------+
| id | name | math | english | chinese |
+----+-----------+------+---------+---------+
| 7 | 宋公明 | 65 | 30 | 75 |
+----+-----------+------+---------+---------+
1 row in set (0.00 sec)
插入查询结果
插入查询结果就是将查到的数据插入到另一个表格中,也就是insert和select的结合体,语法如下:
mysql
INSERT INTO table_name [(column [, column ...])] SELECT ...
删除表中的重复数据,重复的数据只能在表中有一份,操作如下:
mysql
mysql> create table dup (
-> id int,
-> name varchar(10)
-> );
Query OK, 0 rows affected (0.01 sec)
mysql> insert into dup values (100, 'aaa'), (200, 'ccc'), (200, 'ccc'), (200, 'ccc'), (300, 'bbb'), (300, 'bbb');
Query OK, 6 rows affected (0.00 sec)
Records: 6 Duplicates: 0 Warnings: 0
-- 创建一个格式一样的表
mysql> create table nodup like dup;
Query OK, 0 rows affected (0.02 sec)
-- 将查询到的数据使用distinct修饰之后插入到新表中
mysql> insert into nodup select distinct * from dup;
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
-- 表格重命名
mysql> rename table dup to olddup, nodup to dup;
Query OK, 0 rows affected (0.01 sec)
mysql> select * from dup;
+------+------+
| id | name |
+------+------+
| 100 | aaa |
| 200 | ccc |
| 300 | bbb |
+------+------+
3 rows in set (0.00 sec)
对于如上为何需要使用rename来完成,这是因为为了保持原子操作,原来的表可能正在进行数据操作,所以不宜直接在原表上操作,直接将另一个表的名字修改为当前表即可,这样再次操作的时候就是在新表上操作了。
update修改
update语法:
mysql
UPDATE table_name SET column = expr [, column = expr ...]
[WHERE ...] [ORDER BY ...] [LIMIT ...]
查询结果列更新
就是将查询到的特定结果进行更新修改,如下:
mysql
mysql> update exam_result set math = 80 where name = '孙悟空';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> SELECT name, math FROM exam_result WHERE name = '孙悟空';
+-----------+------+
| name | math |
+-----------+------+
| 孙悟空 | 80 |
+-----------+------+
1 row in set (0.00 sec)
mysql> update exam_result set math = 60, chinese = 70 where name = '曹孟德';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> SELECT name, math, chinese FROM exam_result WHERE name = '曹孟德';
+-----------+------+---------+
| name | math | chinese |
+-----------+------+---------+
| 曹孟德 | 60 | 70 |
+-----------+------+---------+
1 row in set (0.01 sec)
一次更新多行数据
假若我们需要将总成绩倒数前三的同学的数学成绩加上30分,应该如何进行操作,如下:
mysql
mysql> select name, math, math + english + chinese 总分 from exam_result order by 总分 limit 3;
+-----------+------+--------+
| name | math | 总分 |
+-----------+------+--------+
| 宋公明 | 65 | 170 |
| 刘玄德 | 85 | 185 |
| 曹孟德 | 60 | 197 |
+-----------+------+--------+
3 rows in set (0.00 sec)
mysql> update exam_result set math = math + 30 order by chinese + english + math limit 3;
Query OK, 3 rows affected (0.00 sec)
Rows matched: 3 Changed: 3 Warnings: 0
mysql> select name, math, math + english + chinese 总分 from exam_result where name in ('宋公明', '刘玄德', '曹孟德');
+-----------+------+--------+
| name | math | 总分 |
+-----------+------+--------+
| 曹孟德 | 90 | 227 |
| 刘玄德 | 115 | 215 |
| 宋公明 | 95 | 200 |
+-----------+------+--------+
3 rows in set (0.00 sec)
如上所示,当我们想要直接对多行进行数据更改,需要提前使用条件将多行数据给筛选出来,然后在进行修改。
把所有同学的语文成绩都变成原来的两倍(修改所有数据的时候就不需要筛选了),如下:
mysql
mysql> update exam_result set chinese = chinese * 2;
Query OK, 7 rows affected (0.00 sec)
Rows matched: 7 Changed: 7 Warnings: 0
mysql> select * from exam_result;
+----+-----------+---------+------+---------+
| id | name | chinese | math | english |
+----+-----------+---------+------+---------+
| 1 | 唐三藏 | 134 | 98 | 56 |
| 2 | 孙悟空 | 174 | 80 | 77 |
| 3 | 猪悟能 | 176 | 98 | 90 |
| 4 | 曹孟德 | 140 | 90 | 67 |
| 5 | 刘玄德 | 110 | 115 | 45 |
| 6 | 孙权 | 140 | 73 | 78 |
| 7 | 宋公明 | 150 | 95 | 30 |
+----+-----------+---------+------+---------+
7 rows in set (0.00 sec)
delete删除数据
删除元素
删除数据的语法:
mysql
DELETE FROM table_name [WHERE ...] [ORDER BY ...] [LIMIT ...]
删除特定元素
删除孙悟空的考试成绩,如下:
mysql
mysql> select * from exam_result where name = '孙悟空';
+----+-----------+---------+------+---------+
| id | name | chinese | math | english |
+----+-----------+---------+------+---------+
| 2 | 孙悟空 | 174 | 80 | 77 |
+----+-----------+---------+------+---------+
1 row in set (0.00 sec)
mysql> delete from exam_result where name = '孙悟空';
Query OK, 1 row affected (0.00 sec)
mysql> select * from exam_result where name = '孙悟空';
Empty set (0.00 sec)
删除整张表的数据
删除整张表的数据需要谨慎,如下:
mysql
-- 创建测试表
mysql> create table delete_test (
-> id int primary key auto_increment,
-> name varchar(10)
-> );
Query OK, 0 rows affected (0.01 sec)
-- 插入数据
mysql> insert into delete_test (name) values ('a'), ('b'), ('c');
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> select * from delete_test;
+----+------+
| id | name |
+----+------+
| 1 | a |
| 2 | b |
| 3 | c |
+----+------+
3 rows in set (0.00 sec)
-- 删除整张表的数据
mysql> delete from delete_test;
Query OK, 3 rows affected (0.00 sec)
mysql> select * from delete_test;
Empty set (0.00 sec)
mysql> insert into delete_test (name) values ('c');
Query OK, 1 row affected (0.00 sec)
-- 重新插入数据,对于auto_increment而言也还是在自增长
mysql> select * from delete_test;
+----+------+
| id | name |
+----+------+
| 4 | c |
+----+------+
1 row in set (0.00 sec)
mysql> show create table delete_test\G
*************************** 1. row ***************************
Table: delete_test
Create Table: CREATE TABLE `delete_test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(10) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
截断数据
截断也是删除数据中的一种,语法如下:
mysql
TRUNCATE [TABLE] table_name
注:截断数据操作需要慎用:
- 只能对整张表进行操作,不能像delete一样针对部分数据操作;
- 实际上MySql不能对数据操作,所以比delete更快,但是truncate在删除数据的时候,并不经过真正的事物,所以无法回避
- truncate不像delete一样,delete不会重置auto_increment的值,turncate会。
测试如下:
mysql
mysql> create table truncate_test (
-> id int primary key auto_increment,
-> name varchar(5)
-> );
Query OK, 0 rows affected (0.02 sec)
mysql> insert into truncate_test (name) values ('a'), ('b'), ('c');
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> select * from truncate_test;
+----+------+
| id | name |
+----+------+
| 1 | a |
| 2 | b |
| 3 | c |
+----+------+
3 rows in set (0.00 sec)
-- 截断整张表,影响的行数是0,所以实际上并没有对数据真正的操作
mysql> truncate truncate_test;
Query OK, 0 rows affected (0.01 sec)
mysql> select * from truncate_test;
Empty set (0.00 sec)
-- 重新插入数据,auto_increment刷新重新开始
mysql> insert into truncate_test (name) values ('d');
Query OK, 1 row affected (0.00 sec)
mysql> select * from truncate_test;
+----+------+
| id | name |
+----+------+
| 1 | d |
+----+------+
1 row in set (0.00 sec)
聚合函数
函数 | 说明 |
---|---|
COUNT([DISTINCT] expr) | 返回查询到的数据的数量 |
SUM([DISTINCT] expr) | 返回查询到的数据的总和,不是数字没有意义 |
AVG([DISTINCT] expr) | 返回查询到的数据的平均值,不是数字没有意义 |
MAX([DISTINCT] expr) | 返回查询到的数据的最大值,不是数字没有意义 |
MIN([DISTINCT] expr) | 返回查询到的数据的最小值,不是数字没有意义 |
count函数
count即为计数函数。当我们使用 * 或者表达式做统计,不会受到null的影响,因为这样统计的是全列的数据,但是当统计的数据是单列数据的时候,就会受到null的影响(null不计入统计)如下:
mysql
mysql> select * from students;
+-----+-------+-----------+------+
| id | sn | name | qq |
+-----+-------+-----------+------+
| 100 | 10010 | 唐三藏 | NULL |
| 102 | 10002 | 沙和尚 | NULL |
| 103 | 10003 | 白龙马 | NULL |
| 105 | 10001 | 唐国公 | NULL |
| 106 | 10008 | 豹子头 | NULL |
| 107 | 10009 | 林黛玉 | 220 |
+-----+-------+-----------+------+
6 rows in set (0.00 sec)
mysql> select count(*) from students;
+----------+
| count(*) |
+----------+
| 6 |
+----------+
1 row in set (0.00 sec)
mysql> select count(1) from students;
+----------+
| count(1) |
+----------+
| 6 |
+----------+
1 row in set (0.00 sec)
mysql> select count(qq) from students;
+-----------+
| count(qq) |
+-----------+
| 1 |
+-----------+
1 row in set (0.00 sec)
统计去重的数据,加上distinct修饰,如下:
mysql
mysql> select count(math) from exam_result;
+-------------+
| count(math) |
+-------------+
| 6 |
+-------------+
1 row in set (0.00 sec)
mysql> select count(distinct math) from exam_result;
+----------------------+
| count(distinct math) |
+----------------------+
| 5 |
+----------------------+
1 row in set (0.00 sec)
sum函数
统计所有同学的数学成绩总和,如下:
mysql
mysql> select sum(math) from exam_result;
+-----------+
| sum(math) |
+-----------+
| 569 |
+-----------+
1 row in set (0.00 sec)
-- 计算数学成绩不合格的总和
mysql> select sum(math) from exam_result where math < 60;
+-----------+
| sum(math) |
+-----------+
| NULL |
+-----------+
1 row in set (0.00 sec)
avg函数
统计平均总分,如下:
mysql
mysql> select avg(chinese + english + math) 平均分 from exam_result;
+-----------+
| 平均分 |
+-----------+
| 297.5 |
+-----------+
1 row in set (0.00 sec)
max/min函數
最大最小函数,使用如下:
mysql
mysql> select max(english) from exam_result;
+--------------+
| max(english) |
+--------------+
| 90 |
+--------------+
1 row in set (0.00 sec)
mysql> select min(math) from exam_result where math > 70;
+-----------+
| min(math) |
+-----------+
| 73 |
+-----------+
1 row in set (0.00 sec)
group by
group by通常对select挑选出的数据进行分组聚合,语法如下:
mysql
select column1, column2, .. from table group by column;
column:指定列名,实际分组就是用该列的不同行数据来进行分组
分组就是按照条件把一张表拆成了多个组,进行各自组内的数据进行聚合统计
如下案例:
创建一个雇员信息表:
EMP员工表
DEPT部门表
SALGRADE工资等级表
如下:
如上所示,假若现在我们需要查询每个部门的平均工资和最高工资,如下:
mysql
mysql> select deptno, max(sal), avg(sal) from emp group by deptno;
+--------+----------+-------------+
| deptno | max(sal) | avg(sal) |
+--------+----------+-------------+
| 10 | 5000.00 | 2916.666667 |
| 20 | 3000.00 | 2175.000000 |
| 30 | 2850.00 | 1566.666667 |
+--------+----------+-------------+
3 rows in set (0.00 sec)
mysql> select ename, deptno, max(sal), avg(sal) from emp group by deptno;
ERROR 1055 (42000): Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'scott.emp.ename' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
如上所示,查询每个部门的平均工资已经最高工资只需要使用group by先将数据分组,然后计算即可。但是当我们想要在筛选出的数据中在显示名字的时候却报错了,这是因为显示我们想要显示的列数据的时候,前提得是group by分组依据中的列。
现在查询每个部门中每种工作的平均工资和最低工资,如下:
mysql
mysql> select job, deptno, min(sal), avg(sal) from emp group by deptno, job;
+-----------+--------+----------+-------------+
| job | deptno | min(sal) | avg(sal) |
+-----------+--------+----------+-------------+
| CLERK | 10 | 1300.00 | 1300.000000 |
| MANAGER | 10 | 2450.00 | 2450.000000 |
| PRESIDENT | 10 | 5000.00 | 5000.000000 |
| ANALYST | 20 | 3000.00 | 3000.000000 |
| CLERK | 20 | 800.00 | 950.000000 |
| MANAGER | 20 | 2975.00 | 2975.000000 |
| CLERK | 30 | 950.00 | 950.000000 |
| MANAGER | 30 | 2850.00 | 2850.000000 |
| SALESMAN | 30 | 1250.00 | 1400.000000 |
+-----------+--------+----------+-------------+
9 rows in set (0.00 sec)
如上所示,当我们想要显示出每个部门中每种工作的工资的时候,只需要在group by后面连续的加上需要分组的列即可。
having
想要显示出平均工资低于2000的部门和它的平均工资,如下:
mysql
mysql> select deptno, avg(sal) 平均工资 from emp group by deptno having 平均工资 < 2000;
+--------+--------------+
| deptno | 平均工资 |
+--------+--------------+
| 30 | 1566.666667 |
+--------+--------------+
1 row in set (0.00 sec)
如上所示,想要在group by下进行二次筛选,只需要在group by后面使用having加上需要筛选的条件即可。所以having的作用就是对group by的结果进行过滤。
我们可以发现having的作用和where很相似,但是其实他们的区别还是很大的,如下,查询除了SMITH员工外的每个部门的每个工作的平均工资低于2000的选项:
mysql
mysql> select deptno, job, avg(sal) from emp where ename!='SMITH' group by deptno, job having avg(sal) < 2000;
+--------+----------+-------------+
| deptno | job | avg(sal) |
+--------+----------+-------------+
| 10 | CLERK | 1300.000000 |
| 20 | CLERK | 1100.000000 |
| 30 | CLERK | 950.000000 |
| 30 | SALESMAN | 1400.000000 |
+--------+----------+-------------+
4 rows in set (0.00 sec)
那么对于以上语句的执行顺序是啥呢?
- from emp先从表中查询到所有数据
- where子句对查询到的数据进行筛选
- group by对筛选的结果进行筛选
- select然后对计算出的结果进行计算
- having最后对计算出的结果进行过滤,得出最终结果
所以where和having的区别首先体现在执行的顺序上,通常where子句的执行顺序会在having之前。并且where和having的使用场景通常也不同,having一般都是和group by搭配使用(也可以单独使用,但是不推荐),where的使用场景更加普遍。
分组也是分表,将一个表的数据分组就是把一张表拆分成多张表,对于MySql中的表不仅仅只是存储在磁盘文件中的才叫表,只要是筛选出来,或者在筛选过程中产生的数据,都是表。