目录
一、Create(创建)
1、insert(插入)
1.1单行数据插入
1.2多行数据插入
1.3插入或者替换更新
2、replace(替换)
二、Retrieve(读取)
1、select
1.1全列查询
1.2指定列查询+利用selsct计算表达式
1.3筛选结果去重
2、where
2.1运算符
2.2找到英语小于60分的同学及其英语成绩
2.3语文成绩在 [80, 90] 分的同学及其语文成绩
2.4数学成绩是 58 或者 59 或者 98 或者 99 分的同学及数学成绩
2.5筛选出叫孙某某的同学及叫孙某的同学(模糊搜索)
2.6语文成绩高于英语成绩的同学
2.7总分在 200 分以下的同学
2.8语文成绩 > 80 并且不姓孙的同学
2.9孙某同学,否则要求总成绩 > 200 并且 语文成绩 < 数学成绩 并且 英语成绩 > 80
2.10 NULL 的查询
3、order by asc/desc(对结果进行升序/降序)
3.1同学及数学成绩,按数学成绩升序/降序显示
3.2查询同学各门成绩,依次按 数学降序,英语降序,语文升序的方式显示
3.3查询同学及总分,由高到低
3.4查询姓孙的同学或者姓曹的同学数学成绩,结果按数学成绩由高到低显示
4、limit(筛选少量结果)
三、Update(更新)
1、将孙悟空的数学成绩变更为 80 分
2、将曹孟德的数学成绩变更为 60 分,语文成绩变更为 70 分
3、将总成绩倒数前三的 3 位同学的数学成绩加上 30 分
4、将所有同学的语文成绩更新为原来的 2 倍
四、Delete(删除)
1、删除孙悟空的考试成绩
2、删除总分最高同学的数据
3、删除整张表数据
3.1delete from
3.2截断表(慎用)
五、将筛选出来的数据插入到数据库中(insert+select)
1、删除表中的的重复记录,重复的数据只能有一份
六、聚合函数
1、COUNT([DISTINCT] expr) 返回查询到的数据的数量
2、SUM([DISTINCT] expr) 返回查询到的数据的 总和,不是数字没有意义
3、AVG([DISTINCT] expr) 返回查询到的数据的 平均值,不是数字没有意义
4、MAX([DISTINCT] expr) 返回查询到的数据的 最大值,不是数字没有意义
5、MIN([DISTINCT] expr)返回查询到的数据的 最小值,不是数字没有意义
七、group by子句:对指定列进行分组查询
1、导入雇员信息表
2、显示每个部门的平均工资和最高工资
3、显示每个部门、每种岗位的平均工资和最低工资
4、显示平均工资低于2000的部门和它的平均工资
5、‘史密斯’不参与统计,显示每个部门、每种岗位的平均工资低于2000的工种
5.1having和where的区别
CRUD : Create(创建), Retrieve(读取),Update(更新),Delete(删除)
一、Create(创建)
语法:
INSERT [INTO] table_name
[(column [, column] ...)]
VALUES (value_list) [, (value_list)] ...
value_list: value, [, value] ...
先创建一张学生表:
--创建学生表
mysql> create table if not exists students(
-> id int unsigned primary key auto_increment,
-> sn int unsigned unique key,
-> name varchar(20) not null,
-> qq varchar(32) unique key
-> );
Query OK, 0 rows affected (0.31 sec)
1、insert(插入)
1.1单行数据插入
指定列单行插入:
mysql> insert into students (sn,name,qq) values (100,'张三','123456');
Query OK, 1 row affected (0.04 sec)
单行全列插入:
mysql> insert into students values (2,101,'李四','222222');
Query OK, 1 row affected (0.05 sec)
1.2多行数据插入
mysql> insert into students (sn,name,qq) values (102,'王五','333333'),(103,'赵六',444444);
Query OK, 2 rows affected (0.04 sec)
Records: 2 Duplicates: 0 Warnings: 0
插入的每条数据逗号隔开,达到一次插入多行的效果。
1.3插入或者替换更新
--打印当前学生表数据
mysql> select* from students;
+----+------+--------+--------+
| id | sn | name | qq |
+----+------+--------+--------+
| 1 | 100 | 张三 | 123456 |
| 2 | 101 | 李四 | 222222 |
| 3 | 102 | 王五 | 333333 |
| 4 | 103 | 赵六 | 444444 |
+----+------+--------+--------+
4 rows in set (0.00 sec)
--重复插入主键为2的值,主键冲突,插入失败
mysql> insert into students values (2,104,'小明','111111');
ERROR 1062 (23000): Duplicate entry '2' for key 'PRIMARY'
--插入变更新,注意作为更新的值可以和插入的值不一样
mysql> insert into students values (2,104,'小明',111111) on duplicate key update sn=104,name='小明',qq='111111';
Query OK, 2 rows affected (0.04 sec)
--打印当前学生表数据,发现id=2的数据被更新
mysql> select* from students;
+----+------+--------+--------+
| id | sn | name | qq |
+----+------+--------+--------+
| 1 | 100 | 张三 | 123456 |
| 2 | 104 | 小明 | 111111 |
| 3 | 102 | 王五 | 333333 |
| 4 | 103 | 赵六 | 444444 |
+----+------+--------+--------+
4 rows in set (0.01 sec)
对数据进行插入,首先数据要合法(相关字段没有被唯一键、主键、外键等进行约束),其次如果插入数据的id已存在,将会更新sn、name和qq而不是插入失败。
2、replace(替换)
--如果替代的数据在表中无冲突,replace将被当成插入
mysql> replace into students (sn,name,qq) values (105,'小红','555555');
Query OK, 1 row affected (0.46 sec)
--打印当前学生表数据,可以看到表中多了一行小红的信息
mysql> select* from students;
+----+------+--------+--------+
| id | sn | name | qq |
+----+------+--------+--------+
| 1 | 100 | 张三 | 123456 |
| 2 | 104 | 小明 | 111111 |
| 3 | 102 | 王五 | 333333 |
| 4 | 103 | 赵六 | 444444 |
| 5 | 105 | 小红 | 555555 |
+----+------+--------+--------+
5 rows in set (0.00 sec)
--再次replace,唯一键存在冲突,小红1的数据将替换小红的数据
mysql> replace into students (sn,name,qq) values (105,'小红1','555555');
Query OK, 2 rows affected (0.02 sec)
--打印当前学生表数据,发现小红1的id变为6
mysql> select* from students;
+----+------+---------+--------+
| id | sn | name | qq |
+----+------+---------+--------+
| 1 | 100 | 张三 | 123456 |
| 2 | 104 | 小明 | 111111 |
| 3 | 102 | 王五 | 333333 |
| 4 | 103 | 赵六 | 444444 |
| 6 | 105 | 小红1 | 555555 |
+----+------+---------+--------+
5 rows in set (0.00 sec)
主键 或者 唯一键 没有冲突,则直接插入;
主键 或者 唯一键 如果冲突,则删除后再插入。
有个细节:当发生替换时,因为主键会自增长并且replace是删除后再替换,所以用于替换的行id将会使用下一个自增的id。如上面的SQL语句中,原先小红的id是5,被替换成小红1后,id变为6。
二、Retrieve(读取)
语法:
SELECT
[DISTINCT] {* | {column [, column] ...}
[FROM table_name]
[WHERE ...]
[ORDER BY column [ASC | DESC], ...]
LIMIT ...
先创建一张成绩表:
--创建成绩表
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.14 sec)
--插入测试数据
mysql> INSERT INTO exam_result (name, chinese, math, english) VALUES
-> ('A', 67, 98, 56),
-> ('B', 87, 78, 77),
-> ('C', 88, 98, 90),
-> ('D', 82, 84, 67),
-> ('E', 55, 85, 45),
-> ('F', 70, 73, 78),
-> ('G', 75, 65, 30);
ds: 7 Duplicates: 0 Warnings: 0Query OK, 7 rows affected (0.03 sec)
Records: 7 Duplicates: 0 Warnings: 0
1、select
1.1全列查询
mysql> select* from exam_result;
+----+------+---------+------+---------+
| id | name | chinese | math | english |
+----+------+---------+------+---------+
| 1 | A | 67 | 98 | 56 |
| 2 | B | 87 | 78 | 77 |
| 3 | C | 88 | 98 | 90 |
| 4 | D | 82 | 84 | 67 |
| 5 | E | 55 | 85 | 45 |
| 6 | F | 70 | 73 | 78 |
| 7 | G | 75 | 65 | 30 |
+----+------+---------+------+---------+
7 rows in set (0.00 sec)
通常情况下不建议使用 * 进行全列查询
1. 查询的列越多,意味着需要传输的数据量越大;
2. 可能会影响到索引的使用。
1.2指定列查询+利用selsct计算表达式
--指定姓名和数学成绩列进行查询
mysql> select name,math from exam_result;
+------+------+
| name | math |
+------+------+
| A | 98 |
| B | 78 |
| C | 98 |
| D | 84 |
| E | 85 |
| F | 73 |
| G | 65 |
+------+------+
7 rows in set (0.00 sec)
--利用selsct计算平均分
mysql> select name,math,(chinese+math+english)/3 from exam_result;
+------+------+--------------------------+
| name | math | (chinese+math+english)/3 |
+------+------+--------------------------+
| A | 98 | 73.66666666666667 |
| B | 78 | 80.66666666666667 |
| C | 98 | 92 |
| D | 84 | 77.66666666666667 |
| E | 85 | 61.666666666666664 |
| F | 73 | 73.66666666666667 |
| G | 65 | 56.666666666666664 |
+------+------+--------------------------+
--觉得计算式太长,可以用as给它重命名为average
mysql> select name,math,(chinese+math+english)/3 as average from exam_result;
+------+------+--------------------+
| name | math | average |
+------+------+--------------------+
| A | 98 | 73.66666666666667 |
| B | 78 | 80.66666666666667 |
| C | 98 | 92 |
| D | 84 | 77.66666666666667 |
| E | 85 | 61.666666666666664 |
| F | 73 | 73.66666666666667 |
| G | 65 | 56.666666666666664 |
+------+------+--------------------+
7 rows in set (0.02 sec)
--当然这个as可以省略
mysql> select name 姓名,math 数学,(chinese+math+english)/3 平均分 from exam_result;
+--------+--------+--------------------+
| 姓名 | 数学 | 平均分 |
+--------+--------+--------------------+
| A | 98 | 73.66666666666667 |
| B | 78 | 80.66666666666667 |
| C | 98 | 92 |
| D | 84 | 77.66666666666667 |
| E | 85 | 61.666666666666664 |
| F | 73 | 73.66666666666667 |
| G | 65 | 56.666666666666664 |
+--------+--------+--------------------+
7 rows in set (0.01 sec)
1.3筛选结果去重
mysql> select distinct math from exam_result;
+------+
| math |
+------+
| 98 |
| 78 |
| 84 |
| 85 |
| 73 |
| 65 |
+------+
6 rows in set (0.00 sec)
2、where
2.1运算符
比较运算符:
运算符 | 说明 |
>, >=, <, <= | 大于,大于等于,小于,小于等于 |
= | 等于,NULL 不安全,例如 NULL = NULL 的结果是 NULL |
<=> | 等于,NULL 安全,例如 NULL <=> NULL 的结果是 TRUE(1) |
!=, <> | 不等于(这两个符号都是NULL不安全的) |
BETWEEN a0 AND a1 | 范围匹配,[a0, a1],如果 a0 <= value <= a1,返回 TRUE(1) |
IN (option, ...) | 如果是 option 中的任意一个,返回 TRUE(1) |
IS NULL | 是 NULL |
IS NOT NULL | 不是 NULL |
LIKE | 模糊匹配。like 'A%'。% 表示任意多个(包括 0 个)任意字符;like 'A_'。_ 表示任意一个字符 |
逻辑运算符:
运算符 | 说明 |
AND | 多个条件必须都为 TRUE(1),结果才是 TRUE(1) |
OR | 任意一个条件为 TRUE(1), 结果为 TRUE(1) |
NOT | 条件为 TRUE(1),结果为 FALSE(0) |
2.2找到英语小于60分的同学及其英语成绩
mysql> select name,english from exam_result where english<60;
+------+---------+
| name | english |
+------+---------+
| A | 56 |
| E | 45 |
| G | 30 |
+------+---------+
3 rows in set (0.00 sec)
2.3语文成绩在 [80, 90] 分的同学及其语文成绩
-- >=和<=
mysql> select name,chinese from exam_result where chinese>=80 and chinese <=90;
+------+---------+
| name | chinese |
+------+---------+
| B | 87 |
| C | 88 |
| D | 82 |
+------+---------+
3 rows in set (0.01 sec)
--between a0 and a1
mysql> select name,chinese from exam_result where chinese between 80 and 90;
+------+---------+
| name | chinese |
+------+---------+
| B | 87 |
| C | 88 |
| D | 82 |
+------+---------+
3 rows in set (0.00 sec)
2.4数学成绩是 58 或者 59 或者 98 或者 99 分的同学及数学成绩
--可以采用多个or
mysql> select name,math from exam_result where math=58 or math=59 or math=98 or math=99;
+------+------+
| name | math |
+------+------+
| A | 98 |
| C | 98 |
+------+------+
2 rows in set (0.02 sec)
--可以用in(......)
mysql> select name,math from exam_result where math in(58,59,98,99);
+------+------+
| name | math |
+------+------+
| A | 98 |
| C | 98 |
+------+------+
2 rows in set (0.00 sec)
2.5筛选出叫孙某某的同学及叫孙某的同学(模糊搜索)
--对新表插入数据
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);
-- like '孙%'找到所有孙姓同学,%代表后面模糊匹配0-n个字符
mysql> select name from exam_result where name like '孙%';
+-----------+
| name |
+-----------+
| 孙悟空 |
| 孙权 |
+-----------+
2 rows in set (0.00 sec)
--like '孙_'找到所有孙某同学,_代表模糊匹配1个字符
mysql> select name from exam_result where name like '孙_';
+--------+
| name |
+--------+
| 孙权 |
+--------+
1 row in set (0.00 sec)
2.6语文成绩高于英语成绩的同学
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)
2.7总分在 200 分以下的同学
mysql> select name,chinese,math,english,chinese+math+english 总分 from exam_result where chinese+math+english<200;
+-----------+---------+------+---------+--------+
| name | chinese | math | english | 总分 |
+-----------+---------+------+---------+--------+
| 刘玄德 | 55 | 85 | 45 | 185 |
| 宋公明 | 75 | 65 | 30 | 170 |
+-----------+---------+------+---------+--------+
2 rows in set (0.00 sec)
该SQL的执行顺序如上图所示。所以where后面直接用总分来表示chinese+math+english是不行的。(去exam_result表里找chinese+math+english小于200的同学进行打印)
2.8语文成绩 > 80 并且不姓孙的同学
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)
2.9孙某同学,否则要求总成绩 > 200 并且 语文成绩 < 数学成绩 并且 英语成绩 > 80
mysql> select name,chinese,math,english,chinese+math+english 总分 from exam_result where name like '孙_' or (chinese+math+english>200 and chinese<math and english>80);
+-----------+---------+------+---------+--------+
| name | chinese | math | english | 总分 |
+-----------+---------+------+---------+--------+
| 猪悟能 | 88 | 98 | 90 | 276 |
| 孙权 | 70 | 73 | 78 | 221 |
+-----------+---------+------+---------+--------+
2 rows in set (0.00 sec)
2.10 NULL 的查询
--创建一个新表
mysql> create table test(
-> id int,
-> name varchar(20)
-> );
Query OK, 0 rows affected (0.09 sec)
--插入数据
mysql> insert into test (id,name) values (1,'张三');
Query OK, 1 row affected (0.04 sec)
mysql> insert into test (id,name) values (null,'张三');
Query OK, 1 row affected (0.05 sec)
mysql> insert into test (id,name) values (1,null);
Query OK, 1 row affected (0.05 sec)
mysql> insert into test (id,name) values (null,null);
Query OK, 1 row affected (0.02 sec)
mysql> insert into test (id,name) values (1,'');
Query OK, 1 row affected (0.01 sec)
--打印表结构
mysql> select* from test;
+------+--------+
| id | name |
+------+--------+
| 1 | 张三 |
| NULL | 张三 |
| 1 | NULL |
| NULL | NULL |
| 1 | |
+------+--------+
5 rows in set (0.02 sec)
null的查询:
mysql> select* from test where name is null;
+------+------+
| id | name |
+------+------+
| 1 | NULL |
| NULL | NULL |
+------+------+
2 rows in set (0.01 sec)
mysql> select* from test where name is not null;
+------+--------+
| id | name |
+------+--------+
| 1 | 张三 |
| NULL | 张三 |
| 1 | |
+------+--------+
3 rows in set (0.01 sec)
注意:null是null,空串是空串,不一样。
mysql> SELECT NULL = NULL, NULL = 1, NULL = 0;
+-------------+----------+----------+
| NULL = NULL | NULL = 1 | NULL = 0 |
+-------------+----------+----------+
| NULL | NULL | NULL |
+-------------+----------+----------+
1 row in set (0.00 sec)
mysql> SELECT NULL <=> NULL, NULL <=> 1, NULL <=> 0;
+---------------+------------+------------+
| NULL <=> NULL | NULL <=> 1 | NULL <=> 0 |
+---------------+------------+------------+
| 1 | 0 | 0 |
+---------------+------------+------------+
1 row in set (0.01 sec)
null之间的比较不能用=,得用<=>或者is null或者is not null
3、order by asc/desc(对结果进行升序/降序)
3.1同学及数学成绩,按数学成绩升序/降序显示
mysql> select name,math from exam_result order by math asc;
+-----------+------+
| name | math |
+-----------+------+
| 张三 | NULL |
| 宋公明 | 65 |
| 孙权 | 73 |
| 孙悟空 | 78 |
| 曹孟德 | 84 |
| 刘玄德 | 85 |
| 唐三藏 | 98 |
| 猪悟能 | 98 |
+-----------+------+
8 rows in set (0.00 sec)
mysql> select name,math from exam_result order by math desc;
+-----------+------+
| name | math |
+-----------+------+
| 唐三藏 | 98 |
| 猪悟能 | 98 |
| 刘玄德 | 85 |
| 曹孟德 | 84 |
| 孙悟空 | 78 |
| 孙权 | 73 |
| 宋公明 | 65 |
| 张三 | NULL |
+-----------+------+
8 rows in set (0.00 sec)
-- ASC 为升序(从小到大)
-- DESC 为降序(从大到小)
-- 默认为 ASC
-- NULL 视为比任何值都小
3.2查询同学各门成绩,依次按 数学降序,英语降序,语文升序的方式显示
mysql> select name,math,english,chinese from exam_result order by math desc,english desc,chinese asc;
+-----------+------+---------+---------+
| name | math | english | chinese |
+-----------+------+---------+---------+
| 猪悟能 | 98 | 90 | 88 |
| 唐三藏 | 98 | 56 | 67 |
| 刘玄德 | 85 | 45 | 55 |
| 曹孟德 | 84 | 67 | 82 |
| 孙悟空 | 78 | 77 | 87 |
| 孙权 | 73 | 78 | 70 |
| 宋公明 | 65 | 30 | 75 |
| 张三 | NULL | NULL | NULL |
+-----------+------+---------+---------+
8 rows in set (0.00 sec)
3.3查询同学及总分,由高到低
mysql> select name,chinese,math,english,chinese+math+english 总分 from exam_result order by 总分 desc;
+-----------+---------+------+---------+--------+
| name | chinese | math | english | 总分 |
+-----------+---------+------+---------+--------+
| 猪悟能 | 88 | 98 | 90 | 276 |
| 孙悟空 | 87 | 78 | 77 | 242 |
| 曹孟德 | 82 | 84 | 67 | 233 |
| 唐三藏 | 67 | 98 | 56 | 221 |
| 孙权 | 70 | 73 | 78 | 221 |
| 刘玄德 | 55 | 85 | 45 | 185 |
| 宋公明 | 75 | 65 | 30 | 170 |
| 张三 | NULL | NULL | NULL | NULL |
+-----------+---------+------+---------+--------+
8 rows in set (0.00 sec)
mysql>
上面的where语句是不能用别名的。但在这里可以使用别名,还是因为顺序的问题。
第一优先级:明确找的是哪张表exam_result
第二优先级:where子句
第三优先级:chinese+math+english 总分
第四优先级:order by 总分 desc(要有合适的数据再进行排序)
第五优先级:limit(数据准备好了,才进行显示)
3.4查询姓孙的同学或者姓曹的同学数学成绩,结果按数学成绩由高到低显示
mysql> select name,math from exam_result where name like '孙%' or name like '曹%' order by math desc limit 3 offset 0;
+-----------+------+
| name | math |
+-----------+------+
| 曹孟德 | 84 |
| 孙悟空 | 78 |
| 孙权 | 73 |
+-----------+------+
3 rows in set (0.00 sec)
4、limit(筛选少量结果)
--从表开始连续读取5行
mysql> select* from exam_result limit 5;
+----+-----------+---------+------+---------+
| 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 |
+----+-----------+---------+------+---------+
5 rows in set (0.01 sec)
--limit 1,3;开始位置1是下标,3是步长
mysql> select* from exam_result limit 1,3;
+----+-----------+---------+------+---------+
| id | name | chinese | math | english |
+----+-----------+---------+------+---------+
| 2 | 孙悟空 | 87 | 78 | 77 |
| 3 | 猪悟能 | 88 | 98 | 90 |
| 4 | 曹孟德 | 82 | 84 | 67 |
+----+-----------+---------+------+---------+
3 rows in set (0.01 sec)
--limit s offset n其中s代表步长,n代表下标
mysql> select* from exam_result limit 3 offset 5;
+----+-----------+---------+------+---------+
| id | name | chinese | math | english |
+----+-----------+---------+------+---------+
| 6 | 孙权 | 70 | 73 | 78 |
| 7 | 宋公明 | 75 | 65 | 30 |
| 8 | 张三 | NULL | NULL | NULL |
+----+-----------+---------+------+---------+
3 rows in set (0.00 sec)
对未知表进行查询时,最好加一条 LIMIT 1,避免因为表中数据过大,查询全表数据导致数据库卡死。
select* from exam_result limit 0,3;
select* from exam_result limit 3,3;
select* from exam_result limit 6,3;
......
select* from exam_result limit 3 offset 0;
select* from exam_result limit 3 offset 3;
select* from exam_result limit 3 offset 6;
进行分页展示。
三、Update(更新)
语法:
UPDATE table_name SET column = expr [, column = expr ...]
[WHERE ...] [ORDER BY ...] [LIMIT ...]
1、将孙悟空的数学成绩变更为 80 分
mysql> update exam_result set math=80 where name ='孙悟空';
Query OK, 1 row affected (0.07 sec)
2、将曹孟德的数学成绩变更为 60 分,语文成绩变更为 70 分
mysql> update exam_result set math=60,chinese=70 where name ='曹孟德';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
3、将总成绩倒数前三的 3 位同学的数学成绩加上 30 分
mysql> update exam_result set math=math+30 order by chinese+math+english asc limit 3;
Query OK, 2 rows affected (0.05 sec)
Rows matched: 3 Changed: 2 Warnings: 0
4、将所有同学的语文成绩更新为原来的 2 倍
mysql> update exam_result set chinese=chinese*2;
Query OK, 7 rows affected (0.04 sec)
Rows matched: 8 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 | 60 | 67 |
| 5 | 刘玄德 | 110 | 115 | 45 |
| 6 | 孙权 | 140 | 73 | 78 |
| 7 | 宋公明 | 150 | 95 | 30 |
| 8 | 张三 | NULL | NULL | NULL |
+----+-----------+---------+------+---------+
8 rows in set (0.00 sec)
没有where子句直接更新全表,需谨慎!update的搞错了危害不亚于delete。
四、Delete(删除)
语法:
DELETE FROM table_name [WHERE ...] [ORDER BY ...] [LIMIT ...]
1、删除孙悟空的考试成绩
mysql> delete from exam_result where name='孙悟空';
Query OK, 1 row affected (0.04 sec)
mysql> select * from exam_result;
+----+-----------+---------+------+---------+
| id | name | chinese | math | english |
+----+-----------+---------+------+---------+
| 1 | 唐三藏 | 134 | 98 | 56 |
| 3 | 猪悟能 | 176 | 98 | 90 |
| 4 | 曹孟德 | 140 | 60 | 67 |
| 5 | 刘玄德 | 110 | 115 | 45 |
| 6 | 孙权 | 140 | 73 | 78 |
| 7 | 宋公明 | 150 | 95 | 30 |
| 8 | 张三 | NULL | NULL | NULL |
+----+-----------+---------+------+---------+
7 rows in set (0.00 sec)
2、删除总分最高同学的数据
mysql> delete from exam_result order by chinese+math+english desc limit 1;
Query OK, 1 row affected (0.02 sec)
3、删除整张表数据
3.1delete from
--准备测试表
mysql> CREATE TABLE for_delete (
-> id INT PRIMARY KEY AUTO_INCREMENT,
-> name VARCHAR(20)
-> );
Query OK, 0 rows affected (0.15 sec)
--插入测试数据
mysql> INSERT INTO for_delete (name) VALUES ('A'), ('B'), ('C');
Query OK, 3 rows affected (0.04 sec)
Records: 3 Duplicates: 0 Warnings: 0
--查看表结构
mysql> select* from for_delete;
+----+------+
| id | name |
+----+------+
| 1 | A |
| 2 | B |
| 3 | C |
+----+------+
3 rows in set (0.00 sec)
--查看创建表时的SQL,可以发现,下一次自增的id值是4
mysql> show create table for_delete\G;
*************************** 1. row ***************************
Table: for_delete
Create Table: CREATE TABLE `for_delete` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=gbk
1 row in set (0.00 sec)
--删除表
mysql> delete from for_delete;
Query OK, 3 rows affected (0.04 sec)
--查看创建表的SQL,发现自增值仍为4
mysql> show create table for_delete\G;
*************************** 1. row ***************************
Table: for_delete
Create Table: CREATE TABLE `for_delete` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=gbk
1 row in set (0.02 sec)
使用delect from这种方式清空表的内容,不会改变自增值。
3.2截断表(慎用)
语法:
TRUNCATE [TABLE] table_name
--准备测试表
mysql> CREATE TABLE for_truncate (
-> id INT PRIMARY KEY AUTO_INCREMENT,
-> name VARCHAR(20)
-> );
Query OK, 0 rows affected (0.14 sec)
--插入测试数据
mysql> INSERT INTO for_truncate (name) VALUES ('A'), ('B'), ('C');
Query OK, 3 rows affected (0.04 sec)
Records: 3 Duplicates: 0 Warnings: 0
--查看表结构
mysql> select* from for_truncate;
+----+------+
| id | name |
+----+------+
| 1 | A |
| 2 | B |
| 3 | C |
+----+------+
3 rows in set (0.01 sec)
--查看创建表时的SQL,可以发现,下一次自增的id值是4
5mysql> show create table for_truncate\G;
*************************** 1. row ***************************
Table: for_truncate
Create Table: CREATE TABLE `for_truncate` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=gbk
1 row in set (0.01 sec)
--删除表中数据
mysql> truncate for_truncate;
Query OK, 0 rows affected (0.21 sec)
--查看创建表时的SQL,发现AUTO_INCREMENT字段没了
mysql> show create table for_truncate\G;
*************************** 1. row ***************************
Table: for_truncate
Create Table: CREATE TABLE `for_truncate` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=gbk
1 row in set (0.01 sec)
--新插入一条数据
mysql> insert into for_truncate (name) values ('E');
Query OK, 1 row affected (0.04 sec)
--查看表结构,发现id从1开始
mysql> select* from for_truncate;
+----+------+
| id | name |
+----+------+
| 1 | E |
+----+------+
1 row in set (0.00 sec)
--查看创建表的SQL,出现自增字段,下一次自增值是2
mysql> show create table for_truncate\G;
*************************** 1. row ***************************
Table: for_truncate
Create Table: CREATE TABLE `for_truncate` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=gbk
1 row in set (0.00 sec)
truncate操作慎用
1. 只能对整表操作,不能像 DELETE 一样针对部分数据操作;
2. MySQL不会把truncate的操作记录记录在日志里(DELETE会),所以它比 DELETE 更快,但是TRUNCATE在删除数据的时候,并不经过真正的事物,所以无法回滚
3. truncate在清空表时,会初始化自增值。
五、将筛选出来的数据插入到数据库中(insert+select)
INSERT INTO table_name [(column [, column ...])] SELECT ...
1、删除表中的的重复记录,重复的数据只能有一份
制造一份原始数据:
--创建表结构
mysql> CREATE TABLE duplicate_table (id int, name varchar(20));
Query OK, 0 rows affected (0.26 sec)
--插入测试数据
mysql> INSERT INTO duplicate_table VALUES
-> (100, 'aaa'),
-> (100, 'aaa'),
-> (200, 'bbb'),
-> (200, 'bbb'),
-> (200, 'bbb'),
-> (300, 'ccc');
Query OK, 6 rows affected (0.03 sec)
Records: 6 Duplicates: 0 Warnings: 0
去重思路:1、创建一张属性和原表一样的空表
--创建一张属性和duplicate_table一样的表no_duplicate_table(空表)
mysql> create table no_duplicate_table like duplicate_table;
Query OK, 0 rows affected (0.23 sec)
--它是空表
mysql> select* from no_duplicate_table;
Empty set (0.01 sec)
--但是属性和duplicate_table一样
mysql> desc no_duplicate_table;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| name | varchar(20) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.02 sec)
2、利用distinct筛选出原表中去重后的数据
--对原表select出来的结果insert进新表中
mysql> insert into no_duplicate_table select distinct * from duplicate_table;
Query OK, 3 rows affected (0.05 sec)
Records: 3 Duplicates: 0 Warnings: 0
--查看新表数据
mysql> select* from no_duplicate_table;
+------+------+
| id | name |
+------+------+
| 100 | aaa |
| 200 | bbb |
| 300 | ccc |
+------+------+
3 rows in set (0.01 sec)
3、将原表名字修改为其他,将新表数据修改为原表名字(狸猫换太子)
--改名
mysql> rename table duplicate_table to old_duplicate_table,no_duplicate_table to duplicate_table;
Query OK, 0 rows affected (0.17 sec)
--查看表
mysql> select* from duplicate_table;
+------+------+
| id | name |
+------+------+
| 100 | aaa |
| 200 | bbb |
| 300 | ccc |
+------+------+
3 rows in set (0.02 sec)
我们在改名前已经准备好了新表,通过重命名表,实现原子的去重操作。
这里的rename改名就是单纯的改名,其实就是文件名和inode的映射关系的改变。
六、聚合函数
函数 | 说明 |
COUNT([DISTINCT] expr) | 返回查询到的数据的 数量 |
SUM([DISTINCT] expr) | 返回查询到的数据的 总和,不是数字没有意义 |
AVG([DISTINCT] expr) | 返回查询到的数据的 平均值,不是数字没有意义 |
MAX([DISTINCT] expr) | 返回查询到的数据的 最大值,不是数字没有意义 |
MIN([DISTINCT] expr) | 返回查询到的数据的 最小值,不是数字没有意义 |
1、COUNT([DISTINCT] expr) 返回查询到的数据的数量
mysql> select* from old_duplicate_table;;
+------+------+
| id | name |
+------+------+
| 100 | aaa |
| 100 | aaa |
| 200 | bbb |
| 200 | bbb |
| 200 | bbb |
| 300 | ccc |
+------+------+
6 rows in set (0.01 sec)
--统计去重的名字有几个
mysql> select count(distinct name) 总数 from old_duplicate_table;
+--------+
| 总数 |
+--------+
| 3 |
+--------+
1 row in set (0.00 sec)
--统计共有几行
mysql> select count(*) from old_duplicate_table;
+----------+
| count(*) |
+----------+
| 6 |
+----------+
1 row in set (0.00 sec)
--统计共有几行
mysql> select count(2) from old_duplicate_table;
+----------+
| count(2) |
+----------+
| 6 |
+----------+
1 row in set (0.00 sec)
--统计id小于200的行数
mysql> select count(*) from old_duplicate_table where id<200;
+----------+
| count(*) |
+----------+
| 2 |
+----------+
1 row in set (0.01 sec)
2、SUM([DISTINCT] expr) 返回查询到的数据的 总和,不是数字没有意义
--统计id和
mysql> select sum(id) from old_duplicate_table;
+---------+
| sum(id) |
+---------+
| 1100 |
+---------+
1 row in set (0.00 sec)
--统计id的平均值
mysql> select sum(id)/count(*) from old_duplicate_table;
+------------------+
| sum(id)/count(*) |
+------------------+
| 183.3333 |
+------------------+
1 row in set (0.00 sec)
3、AVG([DISTINCT] expr) 返回查询到的数据的 平均值,不是数字没有意义
--统计id的平均值
mysql> select avg(id) from old_duplicate_table;
+----------+
| avg(id) |
+----------+
| 183.3333 |
+----------+
1 row in set (0.00 sec)
4、MAX([DISTINCT] expr) 返回查询到的数据的 最大值,不是数字没有意义
4、MAX([DISTINCT] expr) 返回查询到的数据的 最大值,不是数字没有意义
5、MIN([DISTINCT] expr)返回查询到的数据的 最小值,不是数字没有意义
--查找最小的id
mysql> select min(id) from old_duplicate_table;
+---------+
| min(id) |
+---------+
| 100 |
+---------+
1 row in set (0.01 sec)
--查找id大于150的最小值
mysql> select min(id) from old_duplicate_table where id>150;
+---------+
| min(id) |
+---------+
| 200 |
+---------+
1 row in set (0.00 sec)
七、group by子句:对指定列进行分组查询
分组的意义是为了聚合统计。
select column1, column2, .. from table group by column;
1、导入雇员信息表
--将linux目录下的sql表导入MySQL
mysql> source /home/jly/scott_data.sql;
mysql> use scott;
Database changed
mysql> show tables;
+-----------------+
| Tables_in_scott |
+-----------------+
| dept |
| emp |
| salgrade |
+-----------------+
创建一个雇员信息表(来自oracle 9i的经典测试表)
EMP员工表
DEPT部门表
SALGRADE工资等级表
DROP database IF EXISTS `scott`;
CREATE database IF NOT EXISTS `scott` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
USE `scott`;
DROP TABLE IF EXISTS `dept`;
CREATE TABLE `dept` (
`deptno` int(2) unsigned zerofill NOT NULL COMMENT '部门编号',
`dname` varchar(14) DEFAULT NULL COMMENT '部门名称',
`loc` varchar(13) DEFAULT NULL COMMENT '部门所在地点'
);
DROP TABLE IF EXISTS `emp`;
CREATE TABLE `emp` (
`empno` int(6) unsigned zerofill NOT NULL COMMENT '雇员编号',
`ename` varchar(10) DEFAULT NULL COMMENT '雇员姓名',
`job` varchar(9) DEFAULT NULL COMMENT '雇员职位',
`mgr` int(4) unsigned zerofill DEFAULT NULL COMMENT '雇员领导编号',
`hiredate` datetime DEFAULT NULL COMMENT '雇佣时间',
`sal` decimal(7,2) DEFAULT NULL COMMENT '工资月薪',
`comm` decimal(7,2) DEFAULT NULL COMMENT '奖金',
`deptno` int(2) unsigned zerofill DEFAULT NULL COMMENT '部门编号'
);
DROP TABLE IF EXISTS `salgrade`;
CREATE TABLE `salgrade` (
`grade` int(11) DEFAULT NULL COMMENT '等级',
`losal` int(11) DEFAULT NULL COMMENT '此等级最低工资',
`hisal` int(11) DEFAULT NULL COMMENT '此等级最高工资'
);
insert into dept (deptno, dname, loc)
values (10, 'ACCOUNTING', 'NEW YORK');
insert into dept (deptno, dname, loc)
values (20, 'RESEARCH', 'DALLAS');
insert into dept (deptno, dname, loc)
values (30, 'SALES', 'CHICAGO');
insert into dept (deptno, dname, loc)
values (40, 'OPERATIONS', 'BOSTON');
insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7369, 'SMITH', 'CLERK', 7902, '1980-12-17', 800, null, 20);
insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7499, 'ALLEN', 'SALESMAN', 7698, '1981-02-20', 1600, 300, 30);
insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7521, 'WARD', 'SALESMAN', 7698, '1981-02-22', 1250, 500, 30);
insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7566, 'JONES', 'MANAGER', 7839, '1981-04-02', 2975, null, 20);
insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7654, 'MARTIN', 'SALESMAN', 7698, '1981-09-28', 1250, 1400, 30);
insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7698, 'BLAKE', 'MANAGER', 7839, '1981-05-01', 2850, null, 30);
insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7782, 'CLARK', 'MANAGER', 7839, '1981-06-09', 2450, null, 10);
insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7788, 'SCOTT', 'ANALYST', 7566, '1987-04-19', 3000, null, 20);
insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7839, 'KING', 'PRESIDENT', null, '1981-11-17', 5000, null, 10);
insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7844, 'TURNER', 'SALESMAN', 7698,'1981-09-08', 1500, 0, 30);
insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7876, 'ADAMS', 'CLERK', 7788, '1987-05-23', 1100, null, 20);
insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7900, 'JAMES', 'CLERK', 7698, '1981-12-03', 950, null, 30);
insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7902, 'FORD', 'ANALYST', 7566, '1981-12-03', 3000, null, 20);
insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7934, 'MILLER', 'CLERK', 7782, '1982-01-23', 1300, null, 10);
insert into salgrade (grade, losal, hisal) values (1, 700, 1200);
insert into salgrade (grade, losal, hisal) values (2, 1201, 1400);
insert into salgrade (grade, losal, hisal) values (3, 1401, 2000);
insert into salgrade (grade, losal, hisal) values (4, 2001, 3000);
insert into salgrade (grade, losal, hisal) values (5, 3001, 9999);
2、显示每个部门的平均工资和最高工资
mysql> select* from emp;
+--------+--------+-----------+------+---------------------+---------+---------+--------+
| empno | ename | job | mgr | hiredate | sal | comm | deptno |
+--------+--------+-----------+------+---------------------+---------+---------+--------+
| 007369 | SMITH | CLERK | 7902 | 1980-12-17 00:00:00 | 800.00 | NULL | 20 |
| 007499 | ALLEN | SALESMAN | 7698 | 1981-02-20 00:00:00 | 1600.00 | 300.00 | 30 |
| 007521 | WARD | SALESMAN | 7698 | 1981-02-22 00:00:00 | 1250.00 | 500.00 | 30 |
| 007566 | JONES | MANAGER | 7839 | 1981-04-02 00:00:00 | 2975.00 | NULL | 20 |
| 007654 | MARTIN | SALESMAN | 7698 | 1981-09-28 00:00:00 | 1250.00 | 1400.00 | 30 |
| 007698 | BLAKE | MANAGER | 7839 | 1981-05-01 00:00:00 | 2850.00 | NULL | 30 |
| 007782 | CLARK | MANAGER | 7839 | 1981-06-09 00:00:00 | 2450.00 | NULL | 10 |
| 007788 | SCOTT | ANALYST | 7566 | 1987-04-19 00:00:00 | 3000.00 | NULL | 20 |
| 007839 | KING | PRESIDENT | NULL | 1981-11-17 00:00:00 | 5000.00 | NULL | 10 |
| 007844 | TURNER | SALESMAN | 7698 | 1981-09-08 00:00:00 | 1500.00 | 0.00 | 30 |
| 007876 | ADAMS | CLERK | 7788 | 1987-05-23 00:00:00 | 1100.00 | NULL | 20 |
| 007900 | JAMES | CLERK | 7698 | 1981-12-03 00:00:00 | 950.00 | NULL | 30 |
| 007902 | FORD | ANALYST | 7566 | 1981-12-03 00:00:00 | 3000.00 | NULL | 20 |
| 007934 | MILLER | CLERK | 7782 | 1982-01-23 00:00:00 | 1300.00 | NULL | 10 |
+--------+--------+-----------+------+---------------------+---------+---------+--------+
14 rows in set (0.00 sec)
--按部门对各部门的平均工资和最高工资进行统计
mysql> select deptno,avg(sal),max(sal) from emp group by deptno;
+--------+-------------+----------+
| deptno | avg(sal) | max(sal) |
+--------+-------------+----------+
| 10 | 2916.666667 | 5000.00 |
| 20 | 2175.000000 | 3000.00 |
| 30 | 1566.666667 | 2850.00 |
+--------+-------------+----------+
3 rows in set (0.01 sec)
3、显示每个部门、每种岗位的平均工资和最低工资
多个分组条件的分组查询:
mysql> select deptno,job,avg(sal),max(sal) from emp group by deptno,job;
+--------+-----------+-------------+----------+
| deptno | job | avg(sal) | max(sal) |
+--------+-----------+-------------+----------+
| 10 | CLERK | 1300.000000 | 1300.00 |
| 10 | MANAGER | 2450.000000 | 2450.00 |
| 10 | PRESIDENT | 5000.000000 | 5000.00 |
| 20 | ANALYST | 3000.000000 | 3000.00 |
| 20 | CLERK | 950.000000 | 1100.00 |
| 20 | MANAGER | 2975.000000 | 2975.00 |
| 30 | CLERK | 950.000000 | 950.00 |
| 30 | MANAGER | 2850.000000 | 2850.00 |
| 30 | SALESMAN | 1400.000000 | 1600.00 |
+--------+-----------+-------------+----------+
9 rows in set (0.00 sec)
如果在select筛选后面加一个ename的筛选字段,将报错:
4、显示平均工资低于2000的部门和它的平均工资
1、先统计每一个部门的平均工资(先按部门对平均工资进行分组聚合)
2、再使用having对聚合的结果进行条件判断
mysql> select deptno,avg(sal) as 平均工资 from emp group by deptno having 平均工资<2000;
+--------+--------------+
| deptno | 平均工资 |
+--------+--------------+
| 30 | 1566.666667 |
+--------+--------------+
5、‘史密斯’不参与统计,显示每个部门、每种岗位的平均工资低于2000的工种
mysql> select deptno,job,avg(sal) 平均工资 from emp where ename!='SMITH' group by deptno,job having 平均工资<2000;
+--------+----------+--------------+
| deptno | job | 平均工资 |
+--------+----------+--------------+
| 10 | CLERK | 1300.000000 |
| 20 | CLERK | 1100.000000 |
| 30 | CLERK | 950.000000 |
| 30 | SALESMAN | 1400.000000 |
+--------+----------+--------------+
4 rows in set (0.01 sec)
5.1having和where的区别
1、having和where都可以进行条件筛选,分组聚合只能使用having不能使用where,但是只有一张表的的筛选既可以用having也可用where,但是这种场景不建议使用having(为了区分,不建议混用,where的活让where干)
2、筛选的对象不同,如下图:
3、条件筛选的顺序不同,如下图: