前期准备:
#创建表\ncreate table emp(\nid int not null unique auto_increment,\nname varchar(20) not null,\nsex enum('male','female') not null default 'male',\nage int(3) unsigned not null default 28,\nhire_date date not null,\npost varchar(50),\npost_comment varchar(100),\nsalary double(15,2),\noffice int,\ndepart_id int\n);\n\n#插入数据\ninsert into emp(name,sex,age,hire_date,post,salary,office,depart_id)values\n('jason','male',18,'20170301','张江第一帅形象代言',7300.33,401,1),\n('tom','male',78,'20150302','teacher',1000000.31,401,1),\n('kevin','male',81,'20130305','teacher',8300,401,1),\n('tony','male',73,'20140701','teacher',3500,401,1),\n('owen','male',28,'20121101','teacher',2100,401,1),\n('jack','female',18,'20110211','teacher',9000,401,1),\n('jenny','male',18,'19000301','teacher',30000,401,1),\n('sank','male',48,'20150311','teacher',10000,401,1),\n('哈哈','female',48,'20150311','sale',3000.13,'402','2'),\n('呵呵','female',38,'20101101','sale',2000.35,'402','2'),\n('西西','female',18,'sale','20110312',1000.37,'402','2'),\n('乐乐','female',18,'sale','20160513',3000.29,'402','2'),\n('拉拉','female',28,'sale','20170127',4000.33,'402','2'),\n('僧龙','male',28,'20160311','operation',10000.13,403,3),\n('程咬金','male',18,'19970312','operation',18000.13,403,3),\n('程咬银','female',18,'20130311','operation',20000,403,3),\n('程咬铜','male',18,'20150411','operation',19000,403,3),\n('程咬铁','female',18,'20140512','operation',17000,403,3);
补充:可以使用select * from emp\\G;来更改表的展示模式。
#有可能改过编码后,在插入中文的时候,还是会出现乱码或者空白的现象。那么可以将字符编码统一设置成GBK,因为有的Window电脑比较老,默认编码是GBK。
sql的书写顺序建议:where约束条件:几个重要关键字的执行顺序:
select id,name from emp where id > 3;
执行顺序:
1、from
2、where
3、select
虽然执行顺序和书写顺序不一致,你在写sql语句的时候可能不知道怎么写
你就按照书写顺序的方式写sql,selec * 先用*占位,之后去补全后面的sql语句,最后将*替换成你想要的字段。
作用:对整体数据的筛选操作
题目:\n1、查询id大于等于3小于等于6的数据\nselect id,name,age from emp where id>=3 and id<=6;\nselect id,name from emp where id between 3 and 6;\n\n2、查询薪资是20000或者18000或者17000的数据\nselect * from emp where salary=20000 or salary=18000 or salary=17000;\nselect * from emp where salary in(20000,17000,18000);\n\n3、查询员工姓名中包含字母o的员工的姓名和薪资\nselect name,salary from emp where name like '%o%';\n#%o%的意思是o的前面和后面都可以出现任意多个字符。\n\n4、查询员工姓名是由四个字符组成的姓名和薪资\nselect name,salary from emp where name like '____';\nselect name,salary from emp where char_length(name) = 4;\n\n5、查询id小于3或者大于6的数据\nselect * from emp where id not between 3 and 6;\n\n\n6、查询薪资不在20000,18000,17000范围的数据\nselect * from emp where salary not in (20000,18000,17000);\n\n7、查询岗位描述为空的员工姓名和岗位名,针对null不能用等号,要用is\nselect name,post from emp where post_comment = null; #错\nselect name,post from emp where post_comment is null; #对
应用场景:
统计男女比例
部门平均薪资
一般出现:每个 平均 最高 最低的都要做分组,具体看你的语感
... ...
select * from emp group by post;
#会获取每个部门的第一条数据
分组后最小操作单位应该是组 而不是在组内的单个数据
上述命令在你没限制严格模式的时候是可以正常执行的,返回的是分组之后每个组的第一条数据,但是这不符合分组的规范:分组后不应该考虑单个数据,而应该以组为操作单位(分组后没法直接获得组内单个数据)。
如果开启了严格模式,那么上述命令会报错。
set global sql_mode = 'strict_trans_tables,only_full_group_by';
#开启严格模式以及分组设置。
设置严格模式后分组只能拿到分组的依据
按照什么分组就只能按照什么来划分,不能用*要用post
select post from emp group by post;
按照什么分组就只能拿到分组,其他字段不能直接获取,需要借助一些方法(聚合函数)。
聚合函数:
max
min
sum
count
avg
#1、获取每个部门的最高薪资\nselect post,max(salary) from emp group by post;\n可以取别名\nselect post as'部门' ,max(salary)as'最高薪资'from emp group by post;\n#as可以给字段起别名,也可以省略不写,但不推荐,因为容易降低可读性。\n\n#2、获取每个部门的最低薪资\nselect post,min(salary) from emp group by post;\n\n#3、获取每个部门的平均薪资\nselect post,avg(salary) from emp group by post;\n\n#4、获取每个部门的薪资综合\nselect post,sum(salary) from emp group by post;\n\n#5、获取每个部门的人数\nselect post,count(salary) from emp group by post;\nselect post,count(id) from emp group by post;\nselect post,count(age) from emp group by post;\nselect post,count(post_comment) from emp group by post; #不行,因为post_comment的值是null。\n#count对null没法计数\n\n6、查询分组之后的部门名称和每个部门下所有的员工姓名\nselect post,group_concat(name) from emp group by post;\n#group_concat可以支持你获取分组后的其他字段值,还可以支持拼接操作\nselect post,group_concat(name,'_HAHAHA') from emp group by post;\n#可也以获取多个字段\nselect post,group_concat(name,':'salary) from emp group by post;\n\n#concat不分组的时候用\nselect concat('NAME',name),concat('SAL:',salary) from emp;\n\n# as语法不单单可以给字段起别名还可以给表临时起别名\nselect emp.id,emp.name from emp; = select id,name from emp;\nselect emp.id,emp.name from emp as t1; #错\nselect t1.id,t1.name from emp as t1; #对,但只有当前有效,因为sql语句的执行顺序问题,字段在被提取之前,表名就已经被改为t1了\nselect id,name from emp as t1;#对\n\n#查询每个人的年薪,12薪\nselect name,salary *12 from emp;
分组注意事项:
关键字where和group by同时出现的时候group by 必须在where的后面。因为where会先对整体数据进行过滤之后在分组操作。
聚合函数只能在分组之后使用
select id,name,age from emp where max(salary)> 3000; #报错
where的筛选条件不能使用聚合函数
select max(salary) from emp; #不分组默认整体就是一组
#统计各部门年龄在30岁以上的员工平均工资\n1、先求所以年龄大于30岁的员工\nselect * from emp where age>30;\n2、再对结果进行分组\nselect * from emp where age>30 group by post;\n组合:\nselect post,avg(salary) from emp where age>30 group by post;
having的语法和where是一样的,只不过having是在分组之后进行的过滤操作
即having是可以直接使用聚合函数的
#统计各部门年龄在30岁以上的员工工资并且保留平均工资大于10000的部门。\nselect post,avg(salary) from emp\nwhere age>30\ngroup by post\nhaving avg(salary)>10000;
distinct去重\n##必须是完全一样的数据才可以去重!!!\nselect distinct id,age from emp; #去不了,因为带了主键(id号),就会使得数据不一样。\nselect distinct age from emp;
select * from emp order by salary asc; # 升序排序\nselect * from emp order by salary; # 默认是升序排序 asc可以省略\nselect * from emp order by salary desc; #改为降序\n\nselect * from emp order by age,salary asc;\n#先按照age降序排,如果碰到age相同,则再按照salary升序排 \n\n#统计各部门年龄在10岁以上的员工工资并且保留平均工资大于1000的部门,然后对平均工资进行排序。\nselect post,avg(salary) from emp \nwhere age>10 \ngroup by post\nhaving avg(salary)>1000\norder by avg(salary) desc;
#针对数据过多的情况,我们都是做分页处理。\nselect * from emp limit 3; #只拿3条数据\nselect * from emp limit 0,5; #拿第一条到第五条\nselect * from emp limit 5,5; #6~10\n第一个数字是起始位置,第二个是查询的条数\n\nmysql也支持正则:\nselect *from emp where name regexp '^j.*(n|y)$';\nj开头,中间任意,n或y结尾
#创建2张表\ncreate table dep(id int,\nname varchar(20)\n);\ncreate table enp(\nid int primary key auto_increment,\nname varchar(20),\nsex enum('male','female') not null default 'male',age int,dep_id int)\n;\n#录入数据\ninsert into dep values(200,'技术'),\n(201,'人力资源'),\n(202,'销售'),\n(203,'运营');\ninsert into enp(name,sex,age,dep_id) values\n('jason', 'male',18,200),\n('egon','female',48,201),\n('kevin','male',18,201),\n('nick','male',28,202),\n('owen','male',18,203),\n('jerry','female',18 ,204);
表查询:
可以将两张表一起拼接起来显示
select * from enp,dep; #结果叫 笛卡尔积\nselect * from enp,dep where enp.dep_id = dep.id; #拼表操作
推荐写法:
inner join #内连接\nleft join #左连接\nright join #右连接\nunion #全连接\nselect * from enp inner join dep on enp.dep_id = dep.id;\n#只拼接两张表中共有的数据\ninsert into dep(id,name) values(205,'sale');\nselect * from enp left join dep on enp.dep_id = dep.id;\n#左表所有的数据都展示出来 没有对应的项就用null\nselect * from enp right join dep on enp.dep_id = dep.id;\n#右表所有的数据都展示出来 没有对应的项就用null\n#左右两表所有的数据都展示出来,用法:\nselect * from enp left join dep on enp.dep_id = dep.id\nunion\nselect * from enp right join dep on enp.dep_id = dep.id;
子查询就是我们平时解决问题的思路
分步骤解决问题
第一步
第二部
....
将一个查询语句的结果当做另外一个查询语句的条件使用
#查询部门是技术 或者人力资源的员工信息
1、查询部门的id
select id from dep where name='技术' or name ='人力资源';
2、根据id筛选出合适的员工
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、子查询 一步一步的来