diff --git "a/14 \346\235\216\344\277\212\345\205\264/20220222 MySQL\347\272\246\346\235\237.md" "b/14 \346\235\216\344\277\212\345\205\264/20230222 MySQL\347\272\246\346\235\237.md" similarity index 100% rename from "14 \346\235\216\344\277\212\345\205\264/20220222 MySQL\347\272\246\346\235\237.md" rename to "14 \346\235\216\344\277\212\345\205\264/20230222 MySQL\347\272\246\346\235\237.md" diff --git "a/14 \346\235\216\344\277\212\345\205\264/20230228\350\267\250\350\241\250.md" "b/14 \346\235\216\344\277\212\345\205\264/20230228\350\267\250\350\241\250.md" new file mode 100644 index 0000000000000000000000000000000000000000..82a09e69b92d63f61b87ef841b6229b052d73e11 --- /dev/null +++ "b/14 \346\235\216\344\277\212\345\205\264/20230228\350\267\250\350\241\250.md" @@ -0,0 +1,558 @@ +### 笔记 + +- **什么是分组查询?** + +> 将查询结果按照1个或多个字段进行分组,字段值相同的为一组 +> 其实就是按照某一列进行分类 + +- **分组使用** + +> **SELECT gender from employee GROUP BY gender;** +> +> 根据gender字段来分组,gender字段的全部值只有两个('男'和'女'),所以分为了两组 +> 当group by单独使用时,只显示出每一组的第一条记录 +> 所以group by单独使用时的实际意义不大 + +![img](https://pic3.zhimg.com/80/v2-2dd056cc432e89898c80cbacf78c3dda_720w.webp) + +对这个表进行GROUP BY操作 + +```text +SELECT * FROM employee; +``` + +![img](https://pic3.zhimg.com/80/v2-650d569e895acc26b20d0a0edc2596e6_720w.webp) + +只显示了每一组第一条记录 + +男生的第一个人是张三 女生的第一个人是王五 + +![img](https://pic2.zhimg.com/80/v2-a289b4d4803b3e9869656420f5c87d75_720w.webp) + +所以说GROUP BY 一般不单独使用 + + + +**一般来说 你按照什么分组 就查询什么东西** + +**比如:** + +```sql +select department from employee group by department; +``` + +查询结果如上。 + +**分完组然后呢?** + +- **如何对分组后的结果进行查询?** + +**关键字:group_concat()** + +将职员表 按照部门分组 查询每个部门职员的姓名 + +```sql +select department,group_concat(name) from employee group by department; +``` + +结果如下: + +![img](https://pic2.zhimg.com/80/v2-ae5227cf66ecdc638e79980dede53499_720w.webp) + +------ + +- **GROUP BY + 聚合函数** + +**for example:** + +将职员表 按照部门分组 查询每个部门职员的薪水 和 **薪水总数** + +```sql +select department,group_concat(salary),sum(salary) from employee group by department; +``` + +![img](https://pic1.zhimg.com/80/v2-9b5ca13455b29ebcf2e598d38ea87754_720w.webp) + +> 查询每个部门的名称 以及 每个部门的人数 + +```mysql +select department,group_concat(name),count(*) from employee group by department; +``` + +> 查询每个部门的部门名称 以及 每个部门工资大于1500的人数 + +PS:**先把大于1500的人查出来 再做分组** + +```sql +select department,group_concat(salary),count(*) from employee group by department; +``` + +------ + +**group by + having** + +- 用来分组**查询后**制定一些条件来输出查询结果 +- having的作用和where一样,但having只能用于group by +- 查询工资总和大于9000的部门名称以及工资和 + +```sql +SELECT department,GROUP_CONCAT(salary),SUM(salary) FROM employee +GROUP BY department HAVING SUM(salary) > 9000; +``` + +- having和where的区别 + +> having是在分组后对数据进行过滤 +> where是在分组前对数据进行过滤 +> having后面可以使用分组函数(统计函数) +> where后面不可以使用分组函数 +> where是对分组前记录的条件,如果某行记录没有满足where子句的条件,那么这行记录不会参加分组;而having是对分组后数据的约束 + + + +- 查询工资和大于2000的 工资总和大于6000的部门名称以及工资和 + +```sql +SELECT department,GROUP_CONCAT(salary).SUM(salary) FROM employee +WHERE salary > 2000 +GROUP BY department +HAVING SUNM(salary) > 9000 +ORDER BY SUM(salary) DESC; +//降序排列 +``` + +------ + +**书写顺序** + +![img](https://pic3.zhimg.com/80/v2-166d3cee10b01a68e90af2a5d5ed9866_720w.webp) + +------ + +**Limit的使用** + +![img](https://pic3.zhimg.com/80/v2-cc55920af6e230cfe251bf53dd35a9c6_720w.webp) + +```sql +SELECT * FROM employee LIMIT 3,3; +``` + +**从第三行开始 取三条数据** + +**PS:行是从0开始数的** + +![img](https://pic3.zhimg.com/80/v2-320efb37091a14d6e9b35e997c81941a_720w.webp) + +![img](https://pic1.zhimg.com/80/v2-29ecf40b5281d6f98d6a78ecac889ab8_720w.webp) + +------ + +**limit可以用于分页操作** + +![img](https://pic3.zhimg.com/80/v2-71ce51c3e1d647067bc562f362b88ee6_720w.webp) + +- **什么是分组查询?** + +> 将查询结果按照1个或多个字段进行分组,字段值相同的为一组 +> 其实就是按照某一列进行分类 + +- **分组使用** + +> **SELECT gender from employee GROUP BY gender;** +> +> 根据gender字段来分组,gender字段的全部值只有两个('男'和'女'),所以分为了两组 +> 当group by单独使用时,只显示出每一组的第一条记录 +> 所以group by单独使用时的实际意义不大 + +![img](https://pic3.zhimg.com/80/v2-2dd056cc432e89898c80cbacf78c3dda_720w.webp) + +对这个表进行GROUP BY操作 + +```text +SELECT * FROM employee; +``` + +![img](https://pic3.zhimg.com/80/v2-650d569e895acc26b20d0a0edc2596e6_720w.webp) + +只显示了每一组第一条记录 + +男生的第一个人是张三 女生的第一个人是王五 + +![img](https://pic2.zhimg.com/80/v2-a289b4d4803b3e9869656420f5c87d75_720w.webp) + +所以说GROUP BY 一般不单独使用 + + + +**一般来说 你按照什么分组 就查询什么东西** + +**比如:** + +```text +select department from employee group by department; +``` + +![img](https://pic2.zhimg.com/80/v2-9f78a7bd599627321b0323af525d6ff9_720w.webp) + +查询结果如上。 + +**分完组然后呢?** + +- **如何对分组后的结果进行查询?** + +**关键字:group_concat()** + +将职员表 按照部门分组 查询每个部门职员的姓名 + +```text +select department,group_concat(name) from employee group by department; +``` + +结果如下: + +![img](https://pic2.zhimg.com/80/v2-ae5227cf66ecdc638e79980dede53499_720w.webp) + +------ + +- **GROUP BY + 聚合函数** + +**for example:** + +将职员表 按照部门分组 查询每个部门职员的薪水 和 **薪水总数** + +```text +select department,group_concat(salary),sum(salary) from employee group by department; +``` + +![img](https://pic1.zhimg.com/80/v2-9b5ca13455b29ebcf2e598d38ea87754_720w.webp) + +> 查询每个部门的名称 以及 每个部门的人数 + +```mysql +select department,group_concat(name),count(*) from employee group by department; +``` + +> 查询每个部门的部门名称 以及 每个部门工资大于1500的人数 + +PS:**先把大于1500的人查出来 再做分组** + +```sql +select department,group_concat(salary),count(*) from employee group by department; +``` + +------ + +**group by + having** + +- 用来分组**查询后**制定一些条件来输出查询结果 +- having的作用和where一样,但having只能用于group by +- 查询工资总和大于9000的部门名称以及工资和 + +```sql +SELECT department,GROUP_CONCAT(salary),SUM(salary) FROM employee +GROUP BY department HAVING SUM(salary) > 9000; +``` + +- having和where的区别 + +> having是在分组后对数据进行过滤 +> where是在分组前对数据进行过滤 +> having后面可以使用分组函数(统计函数) +> where后面不可以使用分组函数 +> where是对分组前记录的条件,如果某行记录没有满足where子句的条件,那么这行记录不会参加分组;而having是对分组后数据的约束 + + + +- 查询工资和大于2000的 工资总和大于6000的部门名称以及工资和 + +```sql +SELECT department,GROUP_CONCAT(salary).SUM(salary) FROM employee +WHERE salary > 2000 +GROUP BY department +HAVING SUNM(salary) > 9000 +ORDER BY SUM(salary) DESC; +//降序排列 +``` + +------ + +**书写顺序** + +![img](https://pic3.zhimg.com/80/v2-166d3cee10b01a68e90af2a5d5ed9866_720w.webp) + +------ + +**Limit的使用** + +![img](https://pic3.zhimg.com/80/v2-cc55920af6e230cfe251bf53dd35a9c6_720w.webp) + +```text +SELECT * FROM employee LIMIT 3,3; +``` + +**从第三行开始 取三条数据** + +**PS:行是从0开始数的** + +![img](https://pic3.zhimg.com/80/v2-320efb37091a14d6e9b35e997c81941a_720w.webp) + +![img](https://pic1.zhimg.com/80/v2-29ecf40b5281d6f98d6a78ecac889ab8_720w.webp) + +------ + +**limit可以用于分页操作** + +![img](https://pic3.zhimg.com/80/v2-71ce51c3e1d647067bc562f362b88ee6_720w.webp) + +```mysql +inner join,full outer join,left join,right jion +内部连接 inner join 两表都满足的组合 +full outer 全连 两表相同的组合在一起,A表有,B表没有的数据(显示为null),同样B表有 +A表没有的显示为(null) +A表 left join B表 左连,以A表为基础,A表的全部数据,B表有的组合。没有的为null +A表 right join B表 右连,以B表为基础,B表的全部数据,A表的有的组合。没有的为null + + +查询分析器中执行: +--建表table1,table2: +create table table1(id int,name varchar(10)) +create table table2(id int,score int) +insert into table1 select 1,'lee' +insert into table1 select 2,'zhang' +insert into table1 select 4,'wang' +insert into table2 select 1,90 +insert into table2 select 2,100 +insert into table2 select 3,70 +如表 +------------------------------------------------- +table1|table2| +------------------------------------------------- +idname|idscore| +1lee|190| +2zhang|2100| +4wang|370| +------------------------------------------------- + +以下均在查询分析器中执行 + +一、外连接 +1.概念:包括左向外联接、右向外联接或完整外部联接 + +2.左连接:left join 或 left outer join +(1)左向外联接的结果集包括 LEFT OUTER 子句中指定的左表的所有行,而不仅仅是联接列所匹配的行。如果左表的某行在右表中没有匹配行,则在相关联的结果集行中右表的所有选择列表列均为空值(null)。 +(2)sql语句 +select * from table1 left join table2 on table1.id=table2.id +-------------结果------------- +idnameidscore +------------------------------ +1lee190 +2zhang2100 +4wangNULLNULL +------------------------------ +注释:包含table1的所有子句,根据指定条件返回table2相应的字段,不符合的以null显示 + +3.右连接:right join 或 right outer join +(1)右向外联接是左向外联接的反向联接。将返回右表的所有行。如果右表的某行在左表中没有匹配行,则将为左表返回空值。 +(2)sql语句 +select * from table1 right join table2 on table1.id=table2.id +-------------结果------------- +idnameidscore +------------------------------ +1lee190 +2zhang2100 +NULLNULL370 +------------------------------ +注释:包含table2的所有子句,根据指定条件返回table1相应的字段,不符合的以null显示 + +4.完整外部联接:full join 或 full outer join +(1)完整外部联接返回左表和右表中的所有行。当某行在另一个表中没有匹配行时,则另一个表的选择列表列包含空值。如果表之间有匹配行,则整个结果集行包含基表的数据值。 +(2)sql语句 +select * from table1 full join table2 on table1.id=table2.id +-------------结果------------- +idnameidscore +------------------------------ +1lee190 +2zhang2100 +4wangNULLNULL +NULLNULL370 +------------------------------ +注释:返回左右连接的和(见上左、右连接) + +二、内连接 +1.概念:内联接是用比较运算符比较要联接列的值的联接 + +2.内连接:join 或 inner join + +3.sql语句 +select * from table1 join table2 on table1.id=table2.id +-------------结果------------- +idnameidscore +------------------------------ +1lee190 +2zhang2100 +------------------------------ +注释:只返回符合条件的table1和table2的列 + +4.等价(与下列执行效果相同) +A:select a.*,b.* from table1 a,table2 b where a.id=b.id +B:select * from table1 cross join table2 where table1.id=table2.id (注:cross join后加条件只能用where,不能用on) + +三、交叉连接(完全) + +1.概念:没有 WHERE 子句的交叉联接将产生联接所涉及的表的笛卡尔积。第一个表的行数乘以第二个表的行数等于笛卡尔积结果集的大小。(table1和table2交叉连接产生3*3=9条记录) + +2.交叉连接:cross join (不带条件where...) + +3.sql语句 +select * from table1 cross join table2 +-------------结果------------- +idnameidscore +------------------------------ +1lee190 +2zhang190 +4wang190 +1lee2100 +2zhang2100 +4wang2100 +1lee370 +2zhang370 +4wang370 +------------------------------ +注释:返回3*3=9条记录,即笛卡尔积 + +4.等价(与下列执行效果相同) +A:select * from table1,table2 +``` + +### 作业 + +```mysql +drop database users; +create database users charset=utf8; +use users; +create table Student( +Sno varchar(20) not null comment'学号', +Sname varchar(20) not null comment'学生姓名', +Ssex varchar(20) not null comment'学生性别', +primary key(Sno), +Sbirthday datetime comment'学生出生年月', +Class varchar(20) comment'学生所在班级' +) comment'学生表'; +create table Course( +Cno varchar(20) not null comment'课程号', +Cname varchar(20) not null comment'课程名称', +primary key(Cno), +Tno varchar(20) not null comment'教工编号' +) comment'课程表'; +create table Score( +Sno varchar(20) not null comment'学号', +Cno varchar(20) not null comment'课程号', +primary key(Sno,Cno), +Degree Decimal(4,1) comment'成绩' +) comment'成绩表'; +create table Teacher( +Tno varchar(20) not null comment'教工编号', +Tname varchar(20) not null comment'教工姓名', +Tsex varchar(20) not null comment'教工性别', +Tbirthday datetime comment'教工出生年月', +Prof varchar(20) comment'职称', +primary key(Tno), +Depart varchar(20) not null comment'教工所在部门' +) comment'教师表'; +alter table Course +add foreign key(Tno) references Teacher(Tno); +insert into Student +values +(108,'曾华','男','1977-9-1',95033), +(105,'匡明','男','1975-10-2',95031), +(107,'王丽','女','1976-1-23',95033), +(101,'李军','男','1976-2-20',95033), +(109,'王芳','女','1975-2-10',95031), +(103,'陆君','男','1974-6-3',95031); +set @@foreign_key_checks=0; +insert into Course +values +('3-105','计算机导论',825), +('3-245','操作系统',804), +('6-166','数字电路',856), +('9-888','高等数学',831); +insert into Score +values +(103,'3-245',86), +(105,'3-245',76), +(109,'3-245',68), +(103,'3-105',92), +(105,'3-105',88), +(109,'3-105',76), +(101,'3-105',64), +(107,'3-105',91), +(108,'3-105',78), +(101,'6-166',85), +(107,'6-166',79), +(108,'6-166',81); +insert into Teacher +values +(804,'李诚','男','1958-12-2','副教授','计算机系'), +(856,'张旭','男','1969-3-12','讲师','电子工程系'), +(825,'王萍','女','1972-5-5','助教','计算机系'), +(831,'刘冰','女','1977-8-14','助教','电子工程系'); +set @@foreign_key_checks=1; +-- 1,查询所有学生,都学了哪些课程,要显示学生信息和课程信息/ +select * from Student inner join Course; +-- 2,查询没有学生的教师的所有信息 +select Tname from Student inner join Teacher WHERE Sno having null; +4. 查询 +① 查询Score表中的最高分的学生学号和课程号。 +select Sno,Cno from Score where Degree =92 ; +select Sno,Cno from Score WHERE Degree <=> (Select MAX(Degree) from Score); +② 查询所有学生的Sname、Cno和Degree列。 +select Sname,Cno,Degree from Student cross join Score on Student.Sno = Score.Sno ; +③ 查询所有学生的Sno、Cname和Degree列。 +select Student.Sno,Cname,Degree from Student inner join Course cross join Score on Student.Sno = Score.Sno and Course.Cno = Score.Cno; +④ 查询所有学生的Sname、Cname和Degree列。 +select Sname,Cname,Degree from Student inner join Course cross join Score on Student.Sno = Score.Sno and Course.Cno = Score.Cno ; +⑤ 查询“95033”班学生的平均分。 +select AVG(Degree),Class from Student inner join Score on Student.Sno = Score.Sno where Class=95033; +⑥ 查询选修“3-105”课程的成绩高于“109”号同学成绩的所有同学的记录。 +select Sno from Score where Degree > 76; +select Sno from Score where Degree> (select Degree from Score where Cno = '3-105' and Sno = 109) ; +⑦ 查询score中选学多门课程的同学中分数为非最高分成绩的记录。 +select Degree from Score where Degree < (select MAX(Degree) from Score); +⑧ 查询成绩高于学号为“109”、课程号为“3-105”的成绩的所有记录。 +select * from Score where Degree >76; +select * from Score where Degree> (select Degree from Score where Cno = '3-105' and Sno = 109) ; +⑨ 查询和学号为108的同学同年出生的所有学生的Sno、Sname和Sbirthday列。 +select Sno,Sname,Sbirthday from Student where Sbirthday=1977; +select Sno,Sname,Sbirthday from Student group by Sbirthday having Sbirthday = Sno = 108 and Sbirthday ; +⑩ 查询“张旭“教师任课的学生成绩。 +select Degree from Teacher inner join Score where Tname='张旭'; +11 查询选修某课程的同学人数多于5人的教师姓名。 +select distinct Tname from Score inner join Teacher where Sno >5; +12 查询出“计算机系“教师所教课程的成绩表。 +select distinct Degree from Teacher inner join Score where Depart ='计算机系'; +13 查询“计算机系”与“电子工程系“不同职称的教师的Tname和Prof。 +select Tname,Prof from Teacher where Depart ='计算机系' or Depart ='电子工程系'; +14 查询选修编号为“3-105“课程且成绩至少高于选修编号为“3-245”的同学的Cno、Sno和Degree,并按Degree从高到低次序排序。 +select Cno,Sno,Degree from Score where Cno ='3-105' xor Degree > Cno ='3-245' xor Degree order by Degree desc ; +15 查询选修编号为“3-105”且成绩高于选修编号为“3-245”课程的同学的Cno、Sno和Degree. +select Cno,Sno,Degree from Score where Cno ='3-105' xor Degree > Cno ='3-245' xor Degree; +16 查询成绩比该课程平均成绩低的同学的成绩表。 +select Degree from Score where Degree <(select AVG(Degree) from Score); +17 查询所有任课教师的Tname和Depart. +select Tname,Depart from Teacher; +18 查询所有未讲课的教师的Tname和Depart. +select Tname,Depart from Teacher inner join Course where Cname is null; +19 查询“男”教师及其所上的课程。 +select Tname,Tsex,Cname from Teacher inner join Course where Tsex ='男'; +20 查询最高分同学的Sno、Cno和Degree列。 +select Sno,Cno,Degree from Score where Degree =92; +select Sno,Cno,Degree from Score where Degree = (select MAX(Degree) from Score); +21 查询和“李军”同性别的所有同学的Sname. +select Sname from Student where Ssex ='男' and Sname != '李军'; +22 查询和“李军”同性别并同班的同学Sname. +select Sname from Student where Ssex ='男' and Sname != '李军' and Class ='95033'; +23 查询所有选修“计算机导论”课程的“男”同学的成绩表。 +select Degree from Course inner join Score cross join Student on Student.Sno = Score.Sno where Cname ='计算机导论' and Ssex ='男'; + +``` + diff --git "a/14 \346\235\216\344\277\212\345\205\264/20232.23 \346\237\245\350\257\242select\350\257\255\345\217\245\345\222\214\350\277\220\347\256\227\347\254\246.md" "b/14 \346\235\216\344\277\212\345\205\264/20232.23 \346\237\245\350\257\242select\350\257\255\345\217\245\345\222\214\350\277\220\347\256\227\347\254\246.md" new file mode 100644 index 0000000000000000000000000000000000000000..6b0181a1e8bcb963cc5eaf95d3663d8fe0596e21 --- /dev/null +++ "b/14 \346\235\216\344\277\212\345\205\264/20232.23 \346\237\245\350\257\242select\350\257\255\345\217\245\345\222\214\350\277\220\347\256\227\347\254\246.md" @@ -0,0 +1,361 @@ +# 2.23 查询select语句和运算符 + +### select语句格式: + +```mysql +SELECT 字段列表 FROM 表名称; + +SELECT 字段列表 FROM 表名称 WHERE 条件; +``` + +### 使用别名(临时名称) + +```mysql +select 字段名1 as "别名1", 字段名2 as "别名2" from 表名称 as 别名; +``` + +- 列的别名有空格时,请加双引号。**==列的别名==中没有空格时,双引号可以加也可以不加**。 +- ==**表的别名不能加双引号**==,表的别名中间不能包含空格。 +- as大小写都可以,as也完全可以省略。 + +```mysql +示例: +mysql> select id "学号",name "姓名" from student; ++------+------+ +| 学号 | 姓名 | ++------+------+ +| 1 | 张三 | +| 2 | 李四 | ++------+------+ +2 rows in set (0.00 sec) + +mysql> select id 学号,name 姓名 from student; ++------+------+ +| 学号 | 姓名 | ++------+------+ +| 1 | 张三 | +| 2 | 李四 | ++------+------+ +2 rows in set (0.00 sec) +``` + +### 结果去重 + +mysql可以在查询结果中使用distinct关键字去重。 + +```mysql +select distinct 字段列表 from 表名称 【where 条件】; + +示例: +select distinct did from t_employee; +``` + +### 算术运算符 + +```mysql +加:+ + 在MySQL +就是求和,没有字符串拼接 +减:- +乘:* +除:/ div(只保留整数部分) + div:两个数相除只保留整数部分 + /:数学中的除 +模:% mod + +mysql中没有 +=等运算符 +``` + +### 比较运算符 + +```mysql +大于:> +小于:< +大于等于:>= +小于等于:>= +等于:= 不能用于null判断 +不等于:!= 或 <> 不能用于null判断 +判断是null 用 is null 或 用 <=> null +判断不是null is not null +``` + +### 区间或集合范围比较运算符 + +```mysql +区间范围:between x and y + not between x and y +集合范围:in (x,x,x) + not in(x,x,x) +between ... and ... 结果包含两端的边界 + +示例: +#查询薪资在[10000,15000] +select * from t_employee where salary>=10000 && salary<=15000; +select * from t_employee where salary between 10000 and 15000; + +#查询籍贯在这几个地方的 +select * from t_employee where work_place in ('北京', '浙江', '江西'); + +#查询薪资不在[10000,15000] +select * from t_employee where salary not between 10000 and 15000; + +#查询籍贯不在这几个地方的 +select * from t_employee where work_place not in ('北京', '浙江', '江西'); +``` + +### 模糊匹配比较运算符 + +%:代表任意个字符 + +_:代表一个字符,如果两个下划线代表两个字符 + +```mysql +示例: +#查询名字中包含'冰'字 +select * from t_employee where ename like '%冰%'; + +#查询名字以‘雷'结尾的 +select * from t_employee where ename like '%远'; + +#查询名字以’李'开头 +select * from t_employee where ename like '李%'; + +#查询名字有冰这个字,但是冰的前面只能有1个字 +select * from t_employee where ename like '_冰%'; + +#查询当前mysql数据库的字符集情况 +show variables like '%character%'; +``` + +### 逻辑运算符 + +```mysql +逻辑与:&& 或 and +逻辑或:|| 或 or +逻辑非:! 或 not +逻辑异或: xor + +示例: +#查询薪资高于15000,并且性别是男的员工 +select * from t_employee where salary>15000 and gender='男'; +select * from t_employee where salary>15000 && gender='男'; + +select * from t_employee where salary>15000 & gender='男';#错误得不到值 &按位与 +select * from t_employee where (salary>15000) & (gender='男'); + +#查询薪资高于15000,或者did为1的员工 +select * from t_employee where salary>15000 or did = 1; +select * from t_employee where salary>15000 || did = 1; + +#查询薪资不在[15000,20000]范围的 +select * from t_employee where salary not between 15000 and 20000; +select * from t_employee where !(salary between 15000 and 20000); + +#查询薪资高于15000,或者did为1的员工,两者只能满足其一 +select * from t_employee where salary>15000 xor did = 1; +select * from t_employee where (salary>15000) ^ (did = 1); +``` + +### 关于null值的问题、 + +```mysql +#(1)判断时 +xx is null +xx is not null +xx <=> null + +#(2)计算时 +ifnull(xx,代替值) 当xx是null时,用代替值计算 + +示例: +#查询员工的实发工资,实发工资 = 薪资 + 薪资 * 奖金比例 +select ename , salary + salary * commission_pct "实发工资" from t_employee; #失败,当commission_pct为null,结果都为null + +select ename ,salary , commission_pct, salary + salary * ifnull(commission_pct,0) "实发工资" from t_employee; +``` + +### 位运算符 + +```mysql +左移:<< +右移:>> +按位与:& +按位或:| +按位异或:^ +按位取反:~ +``` + + + +# 作业 + +## 第1题:员工表 + +| **id** | **name** | **sex** | **tel** | **addr** | **salary** | +| ------ | -------- | ------- | ------------ | -------- | ---------- | +| 10001 | 张一一 | 男 | 13456789000 | 广东韶关 | 10010.58 | +| 10002 | 刘小红 | 女 | 13454319000 | 广东江门 | 12010.21 | +| 10003 | 李四 | 男 | 0751-1234567 | 广东佛山 | 10040.11 | +| 10004 | 刘小强 | 男 | 0755-5555555 | 广东深圳 | 15010.23 | +| 10005 | 王艳 | 女 | NULL | 广东广州 | 14050.16 | + +```mysql +CREATE DATABASE test03 CHARSET utf8; +USE test03; + +CREATE TABLE employee( + id INT, + `name` VARCHAR(20), + sex VARCHAR(20), + tel VARCHAR(20), + addr VARCHAR(50), + salary FLOAT +); + +INSERT INTO employee(id,`name`,sex,tel,addr,salary)VALUES +(10001,'张一一','男','13456789000','广东韶关',10010.58), +(10002,'刘小红','女','13454319000','广东江门',12010.21), +(10003,'李四','男','0751-1234567','广东佛山',10040.11), +(10004,'刘小强','男','0755-5555555','广东深圳',15010.23), +(10005,'王艳','男',NULL,'广东广州',14050.16); +``` + +**要求1:**查询出薪资在12000~13000之间的员工信息。 + +```mysql +SELECT * FROM employee WHERE salary BETWEEN 12000 AND 13000; +``` + +**要求2:**查询出姓“刘”的员工的工号,姓名,家庭住址。 + +```mysql +SELECT id,`name`,addr FROM employee WHERE `name` LIKE '刘%'; +``` + +**要求3:**将“李四”的家庭住址改为“广东韶关” + +```mysql +UPDATE employee SET addr = '广东韶关' WHERE `name` = '李四'; +``` + +**要求4:**查询出名字中带“小”的员工 + +```mysql +SELECT `name` FROM employee WHERE `name` LIKE '%小%'; +``` + +**要求5:**查询出薪资高于11000的男员工信息 + +```mysql +SELECT * FROM employee WHERE salary>11000 AND sex='男'; +``` + +**要求6:**查询没有登记电话号码的员工 + +```mysql +SELECT `name` FROM employee WHERE tel is NULL; +``` + +**要求7:**查询薪资高于12000或者家是广东深圳、广州的男员工 + +```mysql +SELECT `name` FROM employee WHERE sex = '男' AND salary = 12000 OR addr = '广东深圳' OR addr='广东广州'; +``` + +**要求8:**查询每个员工的年薪,显示“姓名、年薪” + +```mysql +SELECT `name`,salary FROM employee; +``` + + + +## 第2题:国家信息表 + +countries_info表中存储了国家名称、所属大陆、面积、人口和 GDP 值。 + +```mysql +DROP TABLE IF EXISTS `countries_info`; +CREATE TABLE `countries_info`( + `name` VARCHAR(100), + `continent` VARCHAR(100), + `area` INT, + population INT, + gdp BIGINT +); + +INSERT INTO countries_info VALUES +('Afghanistan','Asia',652230,25500100,20343000000), +('Albania','Europe',28748,2831741,12960000000), +('Algeria','Africa',2381741,37100000,188681000000), +('Andorra','Europe',468,78115,3712000000), +('Angola','Africa',1246700,20609294,100990000000); +``` + +表数据样例: + +```mysql ++-------------+-----------+---------+------------+--------------+ +| name | continent | area | population | gdp | ++-------------+-----------+---------+------------+--------------+ +| Afghanistan | Asia | 652230 | 25500100 | 20343000000 | +| Albania | Europe | 28748 | 2831741 | 12960000000 | +| Algeria | Africa | 2381741 | 37100000 | 188681000000 | +| Andorra | Europe | 468 | 78115 | 3712000000 | +| Angola | Africa | 1246700 | 20609294 | 100990000000 | ++-------------+-----------+---------+------------+--------------+ +``` + +**要求1:** 查询大国 的国家名称、人口和面积。 + +如果一个国家满足下述两个条件之一,则认为该国是 大国 : + +- 面积至少为 300万平方公里(即,3000000 km2) + +- 人口至少为 2500 万(即 25000000) + + ```mysql + SELECT `name`,area,population FROM countries_info WHERE area>3000000 OR population>=25000000; + ``` + +**要求2:**查询属于亚洲的国家名称、所属大陆、面积、人口和 GDP 值 + +```mysql +SELECT * FROM countries_info WHERE continent = 'Asia'; +``` + +**要求3:**查询国土面积不足1万平方公里且人口不走10万人的国家信息 + +```mysql +SELECT * FROM countries_info WHERE area<10000 AND population<100000; +``` + +**要求4:**查询国家名字中包含“o“字母的国家信息 + +```mysql +SELECT * FROM countries_info WHERE `name` LIKE '%o%'; +``` + +**要求5:**查询GDP值超过10000000000的国家信息 + +```mysql +SELECT * FROM countries_info WHERE gdp>10000000000; +``` + +**要求6:**查询每个国家的人均贡献GDP值(GDP/人口总数)并显示为“国家名、人口、GDP值、人均贡献GDP值” + +```mysql +SELECT `name` 国家名,population 人口,gdp GDP值,gdp/population AS 人均贡献GDP值 FROM countries_info; +``` + +**要求7:**查询人均贡献GDP值低于1000的国家信息。 + +```mysql +SELECT * FROM countries_info WHERE gdp/population<1000; +``` + +**要求8:**查询每个国家的人均国土面积(面积/人口总数)并显示为“国家名、面积、人口、人均国土面积值” + +```mysql +SELECT `name` 国家名,population 人口,gdp GDP值,area/population AS 人均国土面积值 FROM countries_info; +``` + diff --git "a/14 \346\235\216\344\277\212\345\205\264/\345\255\220\346\237\245\350\257\242.md" "b/14 \346\235\216\344\277\212\345\205\264/\345\255\220\346\237\245\350\257\242.md" new file mode 100644 index 0000000000000000000000000000000000000000..b1bb9bc190752caf946952c754176e503b7cfe6f --- /dev/null +++ "b/14 \346\235\216\344\277\212\345\205\264/\345\255\220\346\237\245\350\257\242.md" @@ -0,0 +1,264 @@ +### 7大字句 + +1. from : 从哪些表中筛选 +2. on : 关联多表查询时,去除笛卡尔积 +3. where : 从表中筛选的条件 +4. group by : 分组依据 +5. having:在统计结果中再次筛选 +6. order by: 排序 +7. limit:分页 + +必须按照(1)~(7)的顺序 编写字句 + +**from字句** + +```mysql +# 1.from 语句 +select * +from t_employee; +``` + +**on字句** + +```sql +-- (1) on 必须配合 join 使用 +-- on 后面只写关联条件 +-- 所谓的关联条件 是俩表的关联字段的关系 +-- 有n张表关联,就有n-1个关联条件 +-- 两张表关联,就有1个关联条件 +-- 三张表关联,就有2个关联条件 +SELECT * +FROM t_employee INNER JOIN t_department +ON t_employee.did = t_department.did; +``` + +**where语句** + +```sql +# where 子句 在查询结果中筛选 +SELECT * +FROM t_employee INNER JOIN t_department +ON t_employee.did = t_department.did +WHERE gender = '女'; +``` + +**group by** + +```sql +group by -- 分组 +``` + +**having语句** + +```sql +/*having子句也写条件 +where的条件是针对原表中的记录的筛选。where后面不能出现分组函数。 +having子句是对统计结果(分组函数计算后)的筛选。having可以加分组函数。 +*/ +``` + +**limit语句** + +```sql +/*limit子句是用于分页显示结果。 +limit m,n +n:表示最多该页显示几行 +m:表示从第几行开始取记录,第一个行的索引是0 +m = (page-1)*n page表示第几页*/ +``` + +### 子查询 + +子查询 就是嵌套在一个SQL 语句中的查询 SELECT语句可以嵌套在另一个SELECT中,UPDATE,DELETE,INSERT,CREATE语句等。 + +#### select的where或HAVing中嵌套子查询 + +当子查询结果作为外层另一个SQL的过滤条件,通常把子查询嵌入到WHERE或HAVING中。根据子查询结果的情况,分为如下三种情况。 + ++ 单列 单个值 可以直接使用比较运算符如 < > <= >= = != 等于子查询结果进行比较 ++ 子查询结果为单列 多个值 直接 用 IN 或者 NOT IN ++ 单列 单个值 可以直接使用比较运算符如 < > <= >= = != 等于子查询结果进行比较 还可以 搭配 any 、some 、all 等关键字与查询结果进行比较 + +```sql +/*在where或having后面的子查询结果是: +(1)单个值,那么可以用=,>,<,>=,<=,!=这样的运算符和子查询的结果做比较 +(2)多个值,那么需要用in,not in, >all,>any....形式做比较 + 如“<”、“<=”、“>”、“>=”、“=”、“!=”等搭配ANY、SOME、ALL等关键字与查询结果进行比较*/ +``` + +**SELECT中的EXISTS型子查询** + +EXISTS型子查询也是存在外层SELECT的WHERE子句中,不过它和上面的WHERE型子查询的工作模式不相同,所以这里单独讨论它。 + +如果EXISTS关键字后面的参数是一个任意的子查询,系统将对子查询进行运算以判断它是否返回行,如果至少返回一行,那么EXISTS的结果为true,此时外层查询语句将进行查询;如果子查询没有返回任何行,那么EXISTS的结果为false,此时外层查询语句不进行查询。EXISTS和NOT EXISTS的结果只取决于是否返回行,而不取决于这些行的内容,所以这个子查询输入列表通常是无关紧要的。 + +如果EXISTS关键字后面的参数是一个关联子查询,即子查询的WHERE条件中包含与外层查询表的关联条件,那么此时将对外层查询表做循环,即在筛选外层查询表的每一条记录时,都看这条记录是否满足子查询的条件,如果满足就再用外层查询的其他WHERE条件对该记录进行筛选,否则就丢弃这行记录。 + +**SELECT的FROM中嵌套子查询** + +当子查询结果是多列的结果时,通常将子查询放到FROM后面,然后采用给子查询结果取别名的方式,把子查询结果当成一张“动态生成的临时表”使用。 + +## 作业 + +```sql +create database ZyClass2 charset utf8; +use ZyClass2; +create table stuinfo( + stuNO varchar(10) primary key, + stuName varchar(5), + stuSex varchar(2), + stuAge int , + stuAddress varchar(10), + stuSeat int +); + +create table stuExam( + examNO int auto_increment primary key, + stuNO varchar(10) , + writtenExam int, + labExam int, + constraint sn foreign key(stuno) references stuinfo(stuno) +); + +create table stuMarks( + examNo int , + stuID varchar(10), + score int, + constraint en foreign key(examno) references stuexam(examno) +); + +insert into stuinfo values +('s2501','张秋利','男',20,'美国硅谷',1), +('s2502','李斯文','女',18,'湖北武汉',2), +('s2503','马文才','男',18,'湖南长沙',3), +('s2504','欧阳俊雄','女',21,'湖北武汉',4), +('s2505','梅超风','男',16,'湖北武汉',5), +('s2506','陈旋风','男',19,'美国硅谷',6); + + +insert into stuexam values +(1,'s2501',50,70), +(2,'s2502',60,65), +(3,'s2503',86,70), +(4,'s2504',40,80), +(5,'s2505',70,85), +(6,'s2506',85,90); + + +insert into stumarks values +(1,'s2501',88), +(2,'s2501',92), +(3,'s2501',53), +(4,'s2502',60), +(5,'s2502',99), +(6,'s2503',82); + +-- 在如图的数据表上完成以下题目 + +-- 1.查询出年龄比班上平均年龄大的学生的信息 + select * from stuinfo where stuage > (select avg(stuage) from stuinfo); +-- 2.查询出每个学生的学号,姓名,性别和选修课程的最高分(stuMarks) + select i.stuno,stuName,stusex,m.sc + from + stuinfo i,(select stuid, max(score) sc from stumarks group by stuid) m + where i.stuNO=m.stuID ; +-- 3.查询出每个学生的学号,姓名,性别和考试平均分(stuExam) + select si.stuNO,stuname,stusex,round((avg(se.writtenExam+se.labExam)/2),2) 平均值 + from + stuinfo si,stuexam se + where si.stuNO=se.stuNO group by stuno; +-- 4.查询性别是男并且年龄大于等于20的学生的信息(用两种方法实现:普通查询和子查询) + + #普通查询 + select * + from + stuinfo + where stuSex='男' and stuage >='20'; + + #子查询 + select * + from + (select *from stuinfo where stuSex='男') s + where stuage >='20'; + +-- 5.查询出年龄比所有男生年龄都大的女生的信息 + select * + from + stuinfo + where + stuage > all (select stuage from stuinfo where stuSex='男') and stuSex='女'; +-- 6.查询出所有选修课程都及格的学生的信息 (stuMarks) + select distinct si.* + from + stuinfo si right join stumarks sm on si.stuNO=sm.stuID + where + stuno != (select stuid from stumarks where score<60) ; +-- 7.查询出参加考试的学生的信息(用表连接,in二种方法做)(stuMarks) + + #方法一:表连接 + select distinct si.* + from + stuinfo si right join stumarks sm + on si.stuNO=sm.stuID; + + #方法二:in + select * + from + stuinfo + where + stuno in(select distinct stuid from stumarks); + +-- 8.查询出没有参加考试的学生的信息(用表连接,in二种方法做)(stuMarks) + + #方法一:表连接 + select si.* + from + stuinfo si left join stumarks sm + on si.stuNO=sm.stuID + where + stuno != all (select distinct stuid from stumarks); + + #方法二:in + select * + from + stuinfo si left join stumarks sm + on si.stuNO=sm.stuID + where + stuno not in(select distinct stuid from stumarks); + +-- 9.将有一门成绩成绩大于90分的学生的基本信息查询出来(stuMarks) + select * + from + stuinfo where stuno + in + (select stuid from stumarks where score >'90'); +-- 10.查询出平均成绩在80分以上的学生的基本信息(stuMarks) + select * from stuinfo where stuno = + (select stuid from + (select stuid, avg(score) a from stumarks group by stuid) s where a>80); +-- 11.查询出某同学所有考试成绩比“张秋利”同学所有分数都高的学生基本信息(stuMarks) + select si.* + from + stuinfo si left join stuexam se + on si.stuno = se.stuno + where + se.writtenexam > (select writtenexam from stuexam where stuno = 's2501') + and se.labexam > (select labexam from stuexam where stuno = 's2501'); +-- 12.查询出某同学所有考试成绩只需要比“张秋利”同学某个分数高的学生基本信息(stuMarks) + select distinct si.* + from + stuinfo si right join stumarks sm on si.stuno=sm.stuID + where score > any + (select score from stuinfo si right join stumarks sm on si.stuno=sm.stuID where stuname='张秋利') and stuno != 's2501'; +-- 13.查询班上比所有男生年龄都要大的女生的信息 + select * + from stuinfo + where stuage > all + (select stuage from stuinfo where stusex='男') and stusex='女'; +-- 14.查询出只要比某个男生年龄大的女生的信息 + select * + from stuinfo + where stuage > any + (select stuage from stuinfo where stusex='男') and stusex='女'; +``` +