创建一张表:
- -- 创建一张学生表
- CREATE TABLE students (
- id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
- sn INT NOT NULL UNIQUE COMMENT '学号',
- name VARCHAR(20) NOT NULL,
- qq VARCHAR(20)
- );
单行数据 + 全列插入:
- -- 插入两条记录,value_list 数量必须和定义表的列的数量及顺序一致
- -- 注意,这里在插入的时候,也可以不用指定id(当然,那时候就需要明确插入数据到那些列了),那么mysql会使用默认的值进行自增。
-
- INSERT INTO students VALUES (100, 10000, '唐三藏', NULL);
- INSERT INTO students VALUES (101, 10001, '孙悟空', '11111');
多行插入
- INSERT INTO students (id, sn, name) VALUES
- (102, 20001, '曹孟德'),
- (103, 20002, '孙仲谋');
一次可以插入多行数据。
由于 主键 或者 唯一键 对应的值已经存在而导致插入失败。
可以选择性的进行同步更新操作 语法:
- INSERT INTO students (id, sn, name) VALUES (100, 10010, '唐大师')
- on duplicate key update sn = 10010, name = '唐大师';
注意,更新的值不能和其他的主键或唯一键冲突。

如果没有冲突就插入,有冲突就替换。
示例:
replace into students (sn, name) VALUES (20001, '曹阿瞒');

查询语句是使用MySql时频率最高的语句。其中涉及到单表,多表和子查询。
基本语法:
- SELECT
- [DISTINCT] {* | {column [, column] ...}
- [FROM table_name]
- [WHERE ...]
- [ORDER BY column [ASC | DESC], ...]
- LIMIT ...
order by 表示我们要根据哪列进行排序,可以选择倒序还是正序。
where表示查询条件。
limit表示我们筛选出来的结果显示多少条数。
创建测试表
- 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 '英语成绩'
- );

插入测试用例
- 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);
select * from exam_result;

通常情况下,是不建议用 * 查询的:
1.查询的列越多,意味着需要传输的数据量越大。
2.可能会影响到索引的使用。
比如id,name列
select id,name from exam_result;

其实本质也是先把所有的数据查询出来,然后再把指定的列显示出来。
select语句很特殊,它后面的语句就是要被执行的表达式。
比如
select 7 * 9;

或者我们要在查询的时候混入一个10
select id,name,10 from exam_result;

发现真的混入了一个10。
或者再混入一个 1 + 1
select id,name,1+1 from exam_result;

那么我们也可以计算它们的总成绩并命名为total。(语法:在指定列后面直接加 as + (名字))
select id,name,math + chinese + english as total from exam_result;

(as 其实可以省略)
在指定的列前加上distinct
select distinct math from exam_result;

实际查询一般是不会将数据全部查询出来的,一般都会用到条件查询。
需要注意的是,在跟NULL判断的时候是不安全的,它不像C语言里面NULL可以跟0作比较。在MySql中任何数跟NULL比较都是NULL。甚至NULL 跟NULL比较都是没有意义的

如果非要NULL跟NULL比较,可以用<=>
select NULL<=>NULL;

不过就算要比较一个数是否是NULL,也会用 IS NULL 或者 IS NOT NULL。

1.查找数学成绩是 58 或者 59 或者 98 或者 99 分的同学及数学成绩:
可以用or
select math from exam_result where math=58 or math=59 or math=98 or math=99;
但是这样写比较繁琐,我们可以用in
select math from exam_result where math in(58,59,98,99);

2.模糊匹配
a.查找姓孙的同学
select name from exam_result where name like '孙%';

b.查找孙某同学,注意只有俩字
select name from exam_result where name like '孙_';

where后面也是可以跟表达式的。
查询总分低于200分的同学:
select name,chinese + math + english total from exam_result where chinese + math + english < 200;

但是有一个问题,就是这样写起来感觉很繁琐,我们能不能这样写呢?
select name,chinese + math + english total from exam_result where total < 200;
答案是不能的

这里就涉及到SQL语句中执行顺序的问题了。
它的执行顺序依次是:
1.先执行 from exam_result。先告诉mysql从哪个表里面筛选数据。
2.设置筛选条件,也就是 where字句。
3.最后再执行我们要查询哪些列,并且重命名。
所以我们就能理解为什么在where判断的时候不能使用之前的重命名,这是由执行顺序导致的。
另外我们也不能在筛选的时候对数据进行重命名,这是语法不支持的。
语法:
其中NULL参与排序,但是NULL在比较的时候比任何值都要小。
比如分别按数学成绩升序
select name,math from exam_result order by math;

默认asc是升序排序。
降序:
select name,math from exam_result order by math desc;

稍微复杂一点的:
查询各门成绩,依次按照数学降序,英语降序,语文升序的方式显示。
其中它的意思是,如果数学成绩相等的话,就按照英语降序,如果英语又相等的话,那么就按照语文升序。
先看只按数学降序排序
此时唐三藏是在猪悟能前面的,那么我们完整的执行SQL语句
select name,math,english,chinese from exam_result order by math desc,english desc,chinese;

此时猪悟能就跑到前面去了。
另外我们按总分排序的时候可以这样写
select name,math + english + chinese total from exam_result order by total;

我们发现在where的时候不能这样写(不能使用别名),但是在order by这里就可以了。
这里原因归根结底就还是执行顺序问题。
因为order by是先筛选出合适的数据之后,再排序的。
要注意区分把数据筛选出来和把数据显示出来。
语法:
- -- 起始下标为 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 1,防止表中数据过大,查询全表数据导致数据库卡死。
比如我们想查询前两行数据
select * from exam_result limit 2;

此时,这里的2表示从表的开始位置查多少行。
或者我们想从第二行开始,往后查三行。
select * from exam_result limit 2,3;

此时这里逗号前的2表示开始位置,而3表示步长。(下标是从0开始的)
或者还可以这样写
mysql> select * from exam_result limit 3 offset 0;

这里的offset表示的就是从哪里开始,3表示查三行。
所以总结limit的作用就是:
可以作简单的分页查询,每次只需要更改查询的起始位置,就可以每次查询固定行数的数据。
另外limit的本质是显示,它的执行顺序排在order by后面。(在搭配order by使用时)。
语法:
- UPDATE table_name SET column = expr [, column = expr ...]
- [WHERE ...] [ORDER BY ...] [LIMIT ...]
比如:将孙悟空同学的数学成绩改为80
update exam_result set math=80 where name='孙悟空';
注意要加上where条件判断,不然表中所有人的数学成绩都会被修改成80。
再比如:将成绩倒数的三名同学,数学成绩加上30
update exam_result set math=math+30 order by math+chinese+english asc limit 3;
语法;
DELETE FROM table_name [WHERE ...] [ORDER BY ...] [LIMIT ...]
案例1:删除孙悟空同学的数据
delete from exam_result where name='孙悟空';
案例2:删除成绩倒数第一名的同学的数据
delete from exam_result order by math+chinese+english asc limit 1;
案例3:删除表中所有的数据
首先我们要清楚,delete是删除表中数据的,它不会删除表的结构。
delete from exam_reslut;
这个操作一定要慎用,这里我就不执行了。
另外一定要注意,delete不会影响表的结构,它只删除表的数据。比如,我们就算删除了表中所有的数据,它也不会影响自增主键计数器的值。
语法:
TRUNCATE [TABLE] table_name
这个操作要慎用。同时注意它和delete的区别:
语法:
INSERT INTO table_name [(column [, column ...])] SELECT ...
案例:删除表中的重复数据
先创建测试表,并插入数据
- CREATE TABLE duplicate_table (id int, name varchar(20));
-
- -- 插入测试数据
- INSERT INTO duplicate_table VALUES
- (100, 'aaa'),
- (100, 'aaa'),
- (200, 'bbb'),
- (200, 'bbb'),
- (200, 'bbb'),
- (300, 'ccc');
删除重复数据的思路就是:
先创建另一张表,结构相同。
CREATE TABLE no_duplicate_table LIKE duplicate_table;
然后通过以去重查询原表的方式,将查询的结果插入到新表中。
INSERT INTO no_duplicate_table SELECT DISTINCT * FROM duplicate_table;
然后再更改原表和新表的名字,即可。
- RENAME TABLE duplicate_table TO old_duplicate_table,
- no_duplicate_table TO duplicate_table;
还是先创建一个测试表
- 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 '英语成绩'
- );
再插入一些测试数据
- 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);

查记录的个数
select count(*) from exam_result;

其中count()括号里面不是*也可以

示例2:我们想查询表中记录中有多少条有效的数学成绩
select count(math) from exam_result;

注意:NULL是参与计数的。
示例3:如果我们想统计不重复的数据,可以加distinct,但是要注意distinct所加在的位置。
select count(distinct math) from exam_result;

示例4:统计数学成绩总分
select sum(math) from exam_result;

案例4:统计数学平均分
select avg(math) from exam_result;

案例5:统计数学成绩最高的(统计最低的同理)
select max(math) from exam_result;

案例6:统计数学成绩大于80分的最小值
select min(math) from exam_result where math>80;

分组的目的是为了分组之后,方便聚合统计。
在select中使用group by 子句可以对指定列进行分组查询
语法:
select column1, column2, .. from table group by column;
浅看一下员工信息表


员工薪资表
插入了测试数据
部门表

同样插入数据后
还有薪资等级表

同样有测试数据
示例1:显示每个部门的平均工资和最高工资。
select deptno,max(sal) 最高,avg(sal) 平均 from emp group by deptno;

分组(分表),其实就是把一张表按照条件在逻辑上拆成了多个子表,然后分别对各自的子表进行聚合统计。
示例2:显示每个部门的每种岗位的平均工资和最低工资。
据需求要先按部门分组,再按岗位分组,最后再聚合。
select deptno,job,avg(sal) 平均,min(sal) 最低 from emp group by deptno, job;

一般在分组聚合查询时,select后面只能跟两类,一类是跟分组有关的列,比如deptno和job,另一类就是聚合函数,其他的select后面一般不能跟,比如ename(员工姓名),如果查询的话就会报错。
案例3:显示平均工资低于2000的部门和它的最低工资。
这个需求比较复杂:
1.首先我们需要先统计出每一个部门的平均工资。(也就是结果先聚合出来)
2.再进行判断。(对聚合出来的结果进行判断)
我们用having来对聚合后的结果进行判断。
select deptno,avg(sal) deptavg from emp group by deptno having myavg<2000;

这个having经常跟group by搭配使用,作用是对分组进行筛选,跟where有点像。
虽然having和where都是条件筛选,但是它们完全不一样。

比如将刚刚的案例having换成where就会报错。
之前也提到过,分组其实就是分表,将原先的一张表,按筛选条件分成了多张表。
同理,我们每次用where条件筛选的时候,每次筛选出来的结果在逻辑上也是一张表。
比如:查每个部门的每种工作的平均工资低于2000,但是SMITH要离职了, 所以他不参与统计。
select deptno,job avg(sal) myavg from emp where ename!='SMITH' group by deptno,job having myavg < 2000;

总结where和having的区别:
1.where是对具体的任意列进行条件筛选。
2.having是对分组聚合之后的结果进行条件筛选。
所以它们条件筛选的阶段是不同的。
基本的表查询就到这里。
到现在,我们已经认识到了:
不是只有从磁盘上的表结构导入到MySQL而形成的表才叫做表, 中间根据条件筛选出来的,包括最终结果,都可以认为是逻辑上的表。