
我们继续上篇文章所讲的数据查询
匹配固定字符串
select * from instructor where ID = '76543'
select * from instructor where ID = '76543';

通配符(重要!!)
匹配含有通配符的字符串
select * from course where title like 'Intro%';

select * from course where title like '%Biology%';

空值(NULL)
select name from instructor where salary is null;

没有不是空值的
select name from instructor where dept_name = 'Physics' order by name;

select * from instructor order by salary desc, name asc;


select avg(salary) as avg_salary from instructor where dept_name = 'Comp. Sci.';

select max(salary) as salary_max, min(salary) as salary_min from instructor where dept_name = 'Comp. Sci.'

select count(distinct ID) from teaches where semester = 'Spring' and year = 2018;

select count(*) from teaches;

聚集函数处理空值的原则
select sum(salary) from instructor;
select dept_name, avg (salary) as avg_salary from instructor group by dept_name;

Having子句
找出教师平均工资超过42000美元的系
select dept_name,avg(salary) as avg_salary from instructor group by dept_name having avg(salary)>42000;

Having 短语和WHERE子句的区别
select dept_name, ID, avg (salary) from instructor group by dept_name;

连接查询的三种方法
select name, instructor.dept_name, building from instructor, department where instructor.dept_name= department.dept_name;

select name, T.dept_name, building from instructor as T, department as D where T.dept_name= D.dept_name;
select distinct T.name from instructor as T, instructor as S where T.salary > S.salary and S.dept_name = ’Biology’;
利用join关键字连接
语句格式:
SELECT {*|<表达式>,…,<表达式>}
FROM <表名> JOIN <表名> ON <条件表达式>
select name, instructor.dept_name, building from instructor, department where instructor.dept_name= department.dept_name; select name, instructor.dept_name, building from instructor join department on instructor.dept_name= department.dept_name;

这是两个表的内容
select * from instructor, teaches where instructor.ID= teaches.ID; select * from instructor join teaches on instructor.ID= teaches.ID;
select * from instructor natural join teaches
select dept_name, count(distinct ID) as instr_count from instructor natural join teaches where semester = ‘Spring’ and year = 2018 group by dept_name;
在结果中创建带空值的元组,以此来保留在连接中丢失的
那些元组。





select * from instructor natural left outer join teaches;
select ID, name, dept_name from instructor natural left outer join teaches where course_id is null;
考虑查询“找出没有选修任何课程的学生

select * from takes natural right outer join student;

select ID from takes natural right outer join student where course_id is null;
考虑查询: select * from takes right outer join student on takes.ID= student.ID; 等同于: select * from takes natural right outer join student;
只不过第一个查询中属性ID在结果中出现两次
select * from takes right outer join student using (ID);

假设:
instructor(ID, name, dept_name, salary)
teaches(ID, course_id, sec_id, semester, year)
course(course_id, title, dept_name, credits)
考虑查询:列出教师的名字以及他们所讲授课程的名称
select name, title
from instructor natural join teaches natural
join course;
列出教师的名字以及他们所讲授课程的名称
select name, title
from (instructor natural join teaches) join course
using (course_id);
内连接和外连接
SQL把常规连接称作内连接,用inner join表示。
关键词inner是可选的,当join子句中没有使用outer前缀时,
默认的连接类型是inner join。
select *
from student join takes using (ID);
等价于:
select *
from student inner join takes using (ID);
| 连接类型 |
| Inner join |
| Left outer join |
| Right outer join |
| Full outer join |

SQL 作用在关系上的union, intersect和except 运算
分别对应于数学集合论中的∪ , ∩ 和 −。
假设关系c1:在2017年秋季学期开设的所有课程的集合
select course_id from section
where semester = ’Fall’ and year= 2017;

关系c2:在2018年春季学期开设的所有课程的集合:
select course_id from section
where semester = ’Spring’ and year= 2018;

找出在2017年秋季开设,或者在2018年春季开设或两个学
期都开设的所有课程
(select course_id from section where semester = ’Fall’ and year= 2017) union (select course_id from section where semester = ’Spring’ and year= 2018);

与select不同, union运算自动去除重复
(select course_id from section where semester = ’Fall’ and year= 2017) union all (select course_id from section where semester = ’Spring’ and year= 2018);
结果中的重复元组数等于在c1和c2中出现的重复元组数的
和
找出在2017年秋季和2018年春季都开设的课程的集合: (select course_id from section where semester = ’Fall’ and year= 2017) intersect (select course_id from section where semester = ’Spring’ and year= 2018);

保留重复加all
找出在2017年秋季学期开设但不在2018年春季学期开设的
所有课程:
(select course_id
from section
where semester = ’Fall’ and year= 2017)
except
(select course_id
from section
where semester = ’Spring’ and year= 2018);

结果中的重复元组数等于c1中出现的重复元组数减去c2中
出现的重复元组数(前提是此差为正)。
SQL Server数据库中支持关键字:union,intersect和except
MySQL中只支持union关键字
那我们如何在MySQL中实现intersect和except呢?
一个 SELECT-FROM-WHERE语句称为一个查询块
将一个查询块嵌套在另外一个查询块的WHERE子句或FROM子句中的查询称为嵌套查询
子查询是嵌套在另一个查询中的SELECT-FROM-WHERE表达式
查询: 找出在2017年秋季学期开课的教师姓名
SELECT name /*外层查询/父查询*/ FROM instructor WHERE ID IN (SELECT ID /*内层查询/子查询*/ FROM teaches WHERE semester = ’Fall’ and year= 2017 );
不相关子查询:子查询的查询条件不依赖于父查询
相关子查询:子查询的查询条件依赖于父查询
通常用于集合的成员资格,集合的比较以及集合的基数进行检查
任何SELECT-FROM-WHERE表达式返回的结果都是关系,因而可以被插入到另一个SELECT-FROM-WHERE中任何关系可以出现的地方
标量子查询返回包含单个属性的单个元组
(select course_id from section where semester = 'Spring' and year = 2018);
select distinct course_id from section where semester = 'Fall' and year = 2017 and course_id in (select course_id from section where semester = 'Spring' and year = 2018);

找出在2017年秋季学期开设但不在2018年春季学期
开设的所有课程
select distinct course_id from section where semester = ’Fall’ and year= 2017 and course_id not in (select course_id from section where semester = ’Spring’ and year= 2018);

select distinct name from instructor
where name not in ('Mozart','Einstein');

select count(distinct ID) from takes where (course_id, sec_id, semester, year) in (select course_id, sec_id, semester, year from teaches where teaches.ID = 10101);

select distinct T.name from instructor as T, //这里创建两个关系,一个是所有的,一个是生物系的老师 instructor as S where T.salary > S.salary and S.dept_name = 'Biology';

select name from instructor where salary > all (select salary from instructor where dept_name = ’Biology’);

找出平均工资最高的系
select dept_name from instructor group by dept_name having avg (salary) >= all (select avg(salary) from instructor group by dept_name);
> SOME 大于子查询结果中的某个值
> ALL 大于子查询结果中的所有值
< SOME 小于子查询结果中的某个值
< ALL 小于子查询结果中的所有值
>= SOME 大于等于子查询结果中的某个值
>= ALL 大于等于子查询结果中的所有值
<= SOME 小于等于子查询结果中的某个值
<= ALL 小于等于子查询结果中的所有值
= SOME 等于子查询结果中的某个值
=ALL 等于子查询结果中的所有值(通常没有实际意义)
!=(或<>) SOME 不等于子查询结果中的某个值
!=(或<>) ALL 不等于子查询结果中的任何一个值
| = | <>或!= | < | <= | > | >= | |
| SOME | IN | -- | | <=MAX | >MIN | >= MIN |
| ALL | -- | NOT IN | | <= MIN | >MAX | >= MAX |
找出在2017年秋季学期和2018年春季学期同时开设的所有课程
select course_id from section as S where semester = 'Fall' and year= 2017 and exists (select * from section as T where semester = 'Spring' and year= 2018 and S.course_id= T.course_id);

select distinct S.ID, S.name from student as S where not exists ((select course_id from course where dept_name = 'Biology') except /*上面是在生物系的课程id,下面是 全部课程都学的课程id*/ (select T.course_id from takes as T where S.ID = T.ID));
“找出所有在2017年最多开设一次的课程”
select T.course_id from course as T where 1 >= (select count(R.course_id) from section as R where T.course_id= R.course_id and R.year = 2017);

“找出所有在2017年最多开设一次的课程”
select T.course_id from course as T where unique (select R.course_id from section as R where T.course_id= R.course_id and R.year = 2017);
找出所有在2017年最少开设两次的课程”
select T.course_id from course as T where not unique (select R.course_id from section as R where T.course_id= R.course_id and R.year = 2017);
考虑查询 "找出系平均工资超过42000美元的那些系中教师的平均工资"
方法1 使用having子句
select dept_name, avg (salary) as avg_salary from instructor group by dept_name having avg (salary) > 42000;
方法2 在FROM子句中使用
select dept_name, avg_salary from (select dept_name, avg(salary) as avg_salary from instructor group by dept_name) as dept_avg where avg_salary > 42000;

select dept_name from (select dept_name,sum(salary) as sum_salary from instructor
group by dept_name) as total_dept1
where sum_salary = (select max(sum_salary) from
(select dept_name,sum(salary) as sum_salary from instructor
group by dept_name) as total_dept);
with max_budget (value) as (select max(budget) from department) select department from department, max_budget where department.budget = max_budget.value;
with dept_total (dept_name, value) as (select dept_name, sum(salary) from instructor group by dept_name), dept_total_avg(value) as (select avg(value) from dept_total) select dept_name from dept_total, dept_total_avg where dept_total.value >= dept_total_avg.value;
SQL允许子查询出现在返回单个值的表达式能够出现的任何地方,只要该子查询只返回包含单个属性的单个元组。
这样的子查询叫做标量子查询
select dept_name, (select count(*) from instructor where department.dept_name = instructor.dept_name) as num_instructors from department;

让Music系每个修满144学分的学生成为Music系的教师,其工资为18000美元
insert into instructor select ID, name, dept_name, 18000 from student where dept_name = 'Music' and tot_cred > 144;
对工资低于平均数的教师涨5%的工资
update instructor set salary = salary * 0.5 where salary < (select avg(salary) from instructor);
删除在Watson大楼工作的教师元组
delete from instructor where dept_name in ( select dept_name from department where building = 'Watson' );
删除工资低于大学平均工资的教书记录
delete from instructor where salary < (select avg(salary) from instructor);