目录
一、MySQL常用关键字
二、基本命令
1.进入MySQL
2.增删改查
3.数据类型与约束条件
4.表与表之间建关系
5.修改表与复制表
三、练习
1.表准备
2.where约束条件
3.group by分组
4.having分组之后的筛选条件
5.distinct去重
6.order by排序
7.limit限制展示条数
8.正则
四、多表查询
1.表准备
2.表查询
3.子查询
4.知识点补充
库/表:create 增加 show 查询 alter 修改 drop 删除
数据:insert 增加 select 查询 update 修改 delete 删除
模糊查询:like %:匹配任意多个字符 _:匹配任意单个字符
常用字符类型:int整型 varchar字符型 data时间类型 enum枚举 set集合
约束条件:defaule默认值 unique唯一 primary key主键 auto_increment自增
表与表之间建关系:foreign key外键 on update/delete cascade级联更新/删除
一对一:
authordetail key(authordetail_id) references authordetail(id)
on update cascade on delete cascade
一对多:
foreign key(dep_id) references dep(id) on update cascade on delete cascade
多对多:
foreign key(author_id) references author(id) on update cascade on delete cascade,
foreign key(book_id) references book(id) on update cascade on delete cascade
修改表:
修改表名:rename 增加字段:add 删除字段:drop 修改字段:change/modify
复制表:create table 表名 select * from 旧表;
分组:group by 聚合函数:max min sum count avg
分组之后的条件筛选:having(跟where的语法是一致的)
去重:distinct 排序:order by asc升序(asc可以默认省略不写) order by desc(降序)
限制展示条数:limit 0,5 第一个参数是起始位置 第二个参数是展示条数
正则:select * from emp where name regexp '^j.*(n|y)$';
多表查询: inner join内连接 left join左连接 right join右连接 union全连接
mysql -uroot -p # 进入MySQL
quit; exit; # 退出MySQL
mysqladmin -uroot -p原密码 password 新密码
# 设置密码
库的增删改查:
增:create databases 库名 charset='编码格式';
删:drop database 库名;
改:alter database 库名 charset='utf8';
查:show databases; show create database 库名;
表的增删改查:
切换库:use 库名;
增:create table 表名(id int, name char(4));
删:drop table 表名;
改:alter table 表名 modify name char(16);
查:shwo tables; show create table 表名;
创建表的完整语法:
create table 表名(
字段1 类型(宽度) 约束条件,
字段2 类型(宽度) 约束条件,
...
字段n 类型(宽度) 约束条件
);
数据的增删改查:
增:insert into 表名 values(1,'zero');
删:delete from 表名; delete from 表名 where id = 1;
改:update 表名 set name = 'zs' where id = 1;
查:select * from 表名;
基本数据类型:
整型:
tinyint smallint meduimint int bigint
作用:存储年龄 等级 id 号码等等
浮点型:
float double decimal
作用:身高 体重 薪资等等
字符类型:
char定长 varchar变长
作用:姓名 部门等等
char_length统计字段长度
select char_length(name) from 表名;
时间类型:
date:年月日
datetime:年月日时分秒
time:时分秒
枚举与集合类型:
枚举(enum) 多选一
集合(set)多选多
defaule默认值
具体使用:
create table user(
id int,
name char(16),
gender enum('male','female','outhers') defaule 'male',
hobby set('read','book','news')
);
约束条件:
default:默认值
unique唯一:
单列唯一:
create table t1(
id int unique,
name char(16)
);
insert into t1 values(1,'zero'),(1,'king'); 报错
insert into t1 values(1,'zero'),(2,'king');
联合唯一:
ip和port 单个都可以重复 但是加载一起是唯一的
create table t2(
id int,
ip char(16),
port int,
unique(ip,port)
);
insert into t2 values(1,'127.0.0.1',8080);
insert into t2 values(2,'127.0.0.1',8081);
insert into t2 values(3,'127.0.0.2',8080);
insert into t2 values(4,'127.0.0.1',8080); 报错
primary key主键:
单单从约束效果上来看primary key等价于not null + unique非空且唯一
create table t3(id int primary key);
insert into t3 values(null); 报错
insert into t3 values(1),(1); 报错
insert into t3 values(1),(2);
innodb存储引擎在创建表的时候必须要有primary key
一张表中有且只有一个主键 如果你没有设置主键 那么会从上往下搜索直到遇到一个非空且唯一的字段将它自动升级为主键
如果表中没有主键也没有其他任何的非空且唯一 那么innodb常用自己内部提供的一个隐藏字段作为主键字段 并且通常将id/uid/sid字段作为组件
单个组件:
create table t4(id int primary key,name char(16));
联合主键(多个字段联合起来作为表的组件 本质还是一个主键):
create table t5(id int,ip char(16),port int,primary key(ip,port));
auto_increment自增:
create table t6(id int primary key auto_increment,name char(16));
insert into t6(name) values('zero'),('king'),('zs');
注意:auto_increment通常都是加在主键上的 不能给不同字段加
结论:
在创建表的id(数据的唯一标识id,uid,sid)字段的时候
id int primary key auto_increment
delete from 在删除表中数据的时候 主键的自增不会停止
truncate t6 清空表数据并且重置主键
外键:就是用来帮助我们建立表表关系的foreign key
一对多:
1 一对多表关系 外键字段建在多的一方
2 在创建表的时候 一定要先建被关联表
3 在录入数据的时候 也必须先录入被关联表
create table dep(
id int primary key auto_increment,
dep_name char(16),
dep_desc char(32)
);
create table emp(
id int primary key auto_increment,
name char(16),
gender enum('male','female','outhers') defaule 'male',
dep_id int,
foreign key(dep_id) references dep(id)
);
insert into dep(dep_name,dep_desc) values('教学部','教书育人'),('外交部','国际交际'),('技术部','技术能力');
insert into emp(name,dep_id) values('zero',2),('zoop',1),('king',1),('zoo',3);
修改dep表里面是id字段:
update dep set id=200 where id=2; 报错
删除dep表里面的数据
delete from deo; 报错
1 先删除教学部对应的员工数据 之后在删除部门
操作太过繁琐
2 真正做到数据之间有关系
级联更新:on update cascade
级联删除:on delete cascade
create table dep(
id int primary key auto_increment,
dep_name char(16),
dep_desc char(32)
);
create table emp(
id int primary key auto_increment,
name char(16),
gender enum('male','female','outhers') defaule 'male',
dep_id int,
foreign key(dep_id) references dep(id) on update cascade on delete cascade
);
多对多:
creat table book(
id int primary key auto_increment,
title varchar(32),
price int
);
create table author(
id int primary key auto_increment,
name varchar(32),
age int
);
create table book2author(
id int primary key auto_increment,
author_id int,
book_id int,
foreign key(author_id) references author(id)
on update cascade on delete cascade,
foreign key(book_id) references book(id)
on update cascade on delete cascade
);
一对一:
一对一 外键字段建在任意一放都可以 但是推荐你建在查询频率比较高的表中
create table authordetail(
id int primary key auto_increment,
phone int,
addr varchar(64)
);
create table author(
id int primary key auto_increment,
name varchar(32),
age int,
authordetail key(authordetail_id) references authordetail(id)
on update cascade on delete cascade
);
总结:
表关系的建立需要用到foreign key
一对多:外键字段建在多的一方
多对多:开设第三张存储
一对一:外键字段在任意一方都可以 但是推荐建在查询频率比较高的表中
修改表:
MySQL对大小写是不敏感的
修改表名:
alter table 表名 rename 新表名;
增加字段:
alter table 表名 add 字段名 字段类型(宽度) 约束条件;
alter table 表名 add 字段名 字段类型(宽度) 约束条件 first;
alter table 表名 add 字段名 字段类型(宽度) 约束条件 after 字段名;
删除字段:
alter table 表名 drop 字段名;
修改字段:
alter table 表名 modify 字段名 字段类型(宽度) 约束条件;
alter table 表名 change 旧字段名 新字段名 字段类型(宽度) 约束条件;
复制表:
sql语句查询的结果其实也就是一张虚拟表
create table 表名 select * from 旧表; 不能复制主键 外键 索引
create table new_dep select * from dep where id>3;
create table emp(
id int not null unique auto_increment,
name varchar(20) not null,
sex enum('male','female') not null default 'male',
age int(3) unsigned not null default 28,
hire_date date not null,
post varchar(50),
post_comment varchar(100),
salary double(15,2),
office int,
depart_id int
);
# 插入数据
# 三个部门 教学 销售 运营
insert into emp(name,sex,age,hire_date,post,salary,office,depart_id) values
('jason','male',18,'20170301','形象代言',7300.33,401,1),
('tom','male',78,'20150302','teacher',100000.31,401,1), ('kevin','male',81,'20130305','teacher',8300,401,1), ('tony','male',73,'20140701','teacher',3500,401,1), ('owen','male',28,'20121101','teacher',2100,401,1), ('jack','female',18,'20110211','teacher',9000,401,1), ('jenny','male',18,'19000301','teacher',30000,401,1), ('sank','male',48,'20101111','teacher',10000,401,1),
('哈哈','female',48,'20150311','sale',3000.13,402,2),
('呵呵','female',38,'20101101','sale',2000.35,402,2),
('西西','female',18,'20110312','sale',1000.37,402,2),
('乐乐','female',18,'20160513','sale',3000.29,402,2),
('拉拉','female',28,'20170127','sale',4000.33,402,2),
('僧龙','male',28,'20160311','operation',10000.13,403,3),
('程咬金','male',18,'19970312','operation',20000,403,3),
('程咬银','female',18,'20130311','operation',19000,403,3),
('程咬铜','male',18,'20150411','operation',18000,403,3),
('程咬铁','female',18,'20140512','operation',17000,403,3);
# 当表字段特别多 展示的时候错乱 可以使用\G分行展示
select * from emp\G;
# 个别电脑在插入中文的时候还是会出现乱码或者空白的现象 可以将字符编码统一设置成GBK
作用:是对整体数据的一个筛选
# 1 查询id大于等于3小于等于6的数据
select * from emp where id>=3 and id<=6;
select * from emp where id between 3 and 6;
# 2 查询薪资是20000或者18000或者17000的数据
select * from emp where salary=20000 or salary=18000 or salary=17000;
select * from emp where salary in (20000,18000,17000);
# 3 查询员工姓名中包含字母o的员工的姓名和薪资
select name,salary from emp where name like "%o%";
# 4 查询员工姓名是由四个字符组成的姓名和薪资
select name,salary from emp where name like "____";
select name,salary from emp where char_length(name)=4;
# 5 查询id小于3或者id大于6的数据
select * from emp where id not between 3 and 6;
select * from emp where id<3 or id>6;
# 6 查询薪资不在20000,18000,17000 范围的数据
select * from emp where salary not in (20000,18000,17000);
# 7 查询岗位描述为空的员工姓名和岗位 针对null不用等号 用is 语义更明确
select name,post from emp where post_comment = NULL;
select name,post from emp where post_comment is NULL;
set global sel_mode = 'strict_trans_tables,only_full_group_by'; 设置严格模式
设置严格模式之后 分组 默认只能拿到分组的依据
select post from emp group by post;
按照什么分组就只能拿到分组 其他字段不能直接获取 需要借助于一些方法(聚合函数)
聚合函数:max min sum count avg
# 1 获取每个部分的最高薪资
select post,max(salary) from emp group by post;
select post as '部门',max(salary) as '最高薪资' from emp group by post;
select post '部门',max(salary) '最高薪资' from emp group by post;
# as 可以给字段起别名 也可以直接省略不写 但是不推荐 因为省略的话语义不明确 容易错乱
# 2 获取每个部门的最低薪资
select post,min(salary) from emp group by post;
# 3 获取每个部门的平均薪资
select post,avg(salary) from emp group by post;
# 4 获取每个部门的薪资总和
select post,sum(salary) from emp group by post;
# 5 获取每个部门的人数
select post,count(id) from emp group by post;
select post,count(salary) from emp group by post;
select post,count(age) from emp group by post;
select post,count(post_comment) from emp group by post; (null)不行
# 6 查询分组之后的部门名称和每个部门下所有的员工姓名
# group_concat 不单单可以支持你获取分组之后的其他字段值 还支持拼接操作
select post,group_concat(name) from emp group by post;
select post,group_concat(name,"_666") from emp group by post;
select post,group_concat(name,":",salary) from emp group by post;
# concat不分组的时候用
select concat('姓名:',name),concat('工资:',salary) from emp;
# 补充:as语法不单单可以给字段起别名 还可以给表临时起别名
select emp.id,emp.name from emp;
select emp.id,emp.name from emp as t1; # 报错
select t1.id,t1.name from emp as t1;
# 7 查询每个人的年薪 12薪
select name,salary*12 from emp;
分组注意事项:
关键字where和group by 同时出现的时候group by必须在where的后面
where先对整体数据进行过滤之后再分组操作
聚合函数只能在分组之后使用 where筛选条件不能使用聚合函数
select id,name,age from emp where max(salary)>3000; 报错
select max(salary) from emp; 不分组 默认整体就是一组
# 统计各部门年龄在30岁以上的员工平均薪资
1 先求所有年薪大于30岁的员工
select * from emp where age>30;
2 再对结果进行分组
select * from emp where age > 30 group by post;
select post,avg(salary) from emp where age > 30 group by post;
having的语法根据where是一致的 只不过having是在分组之后进行的过滤操作 即having是可以直接使用聚合函数的
# 统计各部门年龄在30岁以上的员工平均工资并且保留平均工资大于10000的部门
select post,avg(salary) from emp where age>30 group by post having avg(salary) > 10000;
一定要注意 必须是完全一样的数据才可以去重
一定不要将主键忽视了 有主键存在的情况下 是不可能去重的
orm 对象关系映射 让不懂sql语句的人也能够操作数据库
select distinct id,age from emp;
select distinct age from emp;
排序:order by asc升序(asc可以默认省略不写) order by desc降序
select * from emp order by salary;
select * from emp order by salary asc;
select * from emp order by salary desc;
# 先按照age降序排 如果碰到age相同 则再按照salary升序排
select * from emp order by age desc,salary asc;
# 统计各部门年龄在10岁以上的员工平均工资并且保留平均工资大于1000的部门,然后对平均工资降序排序
select post,avg(salary) from emp where age>10
group by post having avg(salary)>1000 order by avg(salary) desc;
select * from emp;
针对数据过多的情况 我们通常都是做分页处理
select * from emp limit 3; # 只展示三条数据
select * from emp limit 0,5;
select * from emp limit 5,5;
第一个参数是起始位置 第二个参数是展示条数
select * from emp where name regexp '^j.*(n|y)$';
create table dep( id int, name varchar(20) );
create table enp(
id int primary key auto_increment, name varchar(20),
sex enum('male','female') not null default 'male',
age int,
dep_id int
);
# 插入数据
insert into dep values (200,'技术'),(201,'人力资源'),(202,'销售'),(203,'运营');
insert into enp(name,sex,age,dep_id) values
('jason','male',18,200), ('egon','female',48,201),
('kevin','male',18,201), ('nick','male',28,202),
('owen','male',18,203), ('jerry','female',18,204);
select * from dep,enp; # 结果 笛卡尔值
select * from enp,dep where enp.dep_id=dep.id;
mysql也知道 你在后面查询数据过程中 肯定会经常用到拼表操作 所以特地给你开设了对应的方法 inner join内连接 left join左连接 right join右连接 union全连接
# inner join内连接
select * from enp inner join dep on enp.dep_id = dep.id;
# 只拼接两张表中共有的数据部分
# left join左连接
select * from enp left join dep on enp.dep_id = dep.id;
# 左表所有的数据都展示出来 没有对应的项就用NULL
# right join右连接 i
nsert into dep values (205,'sale');
select * from enp right join dep on enp.dep_id = dep.id;
# 右表所有的数据都展示出来 没有对应的项就用NULL
# union全连接 左右两表所有的数据都展示出来
select * from enp left join dep on enp.dep_id = dep.id union select * from enp right join dep on enp.dep_id = dep.id;
子查询就是我们平时解决问题的思路
分步骤解决问题
将一个查询语句的结果当做另一个查询语句的条件去用
# 查询部门是技术或人力资源的员工信息
1 先获取部门的id号
2 再去员工表里面筛选出对应的员工
select id from dep where name="技术" or name="人力资源";
select name from enp where dep_id in (200,201);
select * from enp where dep_id in (select id from dep where name="技术" or name="人力资源");
总结:
表的查询结果可以作为其他表的查询条件
也可以通过起别名的方式把它作为一张虚拟表根其他表关联
多表查询就两种方式 先拼接表在查询 子查询一步一步来
连表查询:
1 先拿到部门和员工表 拼接之后的结果
2 分析语义得出需要进行分组
select dep.name from enp inner join dep on enp.dep_id = dep.id group by dep.name having avg(age)>25;
涉及到多表操作的时候 一定要加上表的前缀
子查询:
select name from dep where id in (select dep_id from enp group by dep_id having avg(age)>25);
关键字exist:
只返回布尔值 True False
返回True的时候外层查询语句执行
返回False的时候外层查询语句不再执行
select * from enp where exists (select id from dep where id>300);