MySQL 语法整理(3)

本文详细讲解了SQL中复杂的多表查询操作,包括in, notin, exists和with等技巧。通过实例解析如何查找满足特定条件的课程ID、教师工资比较、依赖外部查询的课程匹配,以及使用with创建临时表提高查询效率。
摘要由CSDN通过智能技术生成

继续接着上一篇博客,今天终于终于要讲比较复杂的多表查询啦!

in:查询表的元素是否在另一个表中。听着是不是觉得很简单,我们来看一个例子

/*我想找出满足semester='Fall' AND YEAR = 2009并且semester='Spring' AND YEAR=2010的课程id
此时,我们会想起上一篇博客中讲到的集合交运算,这里in同样可以实现*/
SELECT DISTINCT course_id
 FROM section
 WHERE semester='Fall' AND YEAR = 2009 AND
 course_id IN 
	(SELECT course_id
	FROM section
	WHERE semester='Spring' AND YEAR=2010);

在这里插入图片描述
当然,类似于集合交的操作,我们也可以用另一种写法来实现

/*这是另一种写法,先构造两个表,然后再判断course_id是否相等*/
SELECT DISTINCT A.course_id
FROM (SELECT DISTINCT course_id
	FROM section
	WHERE semester='Fall' AND YEAR = 2009
	) AS A ,
	(SELECT course_id
	FROM section
	WHERE semester='Spring' AND YEAR=2010
	) AS B
WHERE A.course_id = B.course_id;

not in:查询表的元素是否不在另一个表中。与in类似,不过恰恰相反。

/*not inin 类似,当不在就返回true*/
SELECT DISTINCT course_id
 FROM section
 WHERE semester='Fall' AND YEAR=2009 AND
 course_id NOT IN (
 SELECT course_id
FROM section
WHERE semester='Spring' AND YEAR=2010);

/*这里是另一种做法,比较复杂。首先先把2009年秋季并且2010春季也开课的课程找出来,
然后在把2009年秋季的课程找出不在2009年秋,2010春季的课程*/
SELECT B.course_id
FROM(
	SELECT DISTINCT course_id
	FROM section
	WHERE semester='Fall' AND YEAR = 2009 AND
	course_id IN (SELECT course_id
	FROM section
	WHERE semester = 'Spring' AND YEAR = 2010)
	) AS A , section AS B
WHERE B.semester='Fall' AND B.YEAR = 2009 AND B.course_id != A.course_id;

刚刚我们只是一个键进行in 或者 not in 操作,如果多个键值进行时,就要加个括号。

/*这是多个值进行比较,比如主键是多个键的时候,就要这样*/
/*查询的是id为'10101'的老师所教的课程数*/
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');

some表示只要一个为真即可,相当于or。比如两个表进行比较,只要A表的某个记录对任意一个B表的记录满足条件,那么就将A表该记录保存到结果表中。

/*这里是找出只要比计算机系最低工资高的老师的名字*/
SELECT NAME
 FROM instructor
 WHERE salary > SOME -- 因为最低工资的老师的工资不会满足大于条件,所以会被排除
	(SELECT salary
	FROM instructor
	WHERE dept_name='Comp. Sci.');

all:相当于and,要全为真才行。

/*这里意思是找出比计算机系所有老师的工资都要高的老师的名字*/
SELECT NAME
 FROM instructor
 WHERE salary > ALL 
	(SELECT salary
	FROM instructor
	WHERE dept_name='Comp. Sci.');

我们可以结合之前学习的分组group by 和having来进行一些组合查询。这里给几个例子:

/*这里要查询哪个系的平均工资最高*/
/*这里由于要各个系比较,因此要用到group by,值得注意,>= 不能换成 >
因为假设某个系是最大的,最大的总不能比自己还要大吧!*/
SELECT dept_name
 FROM instructor
 GROUP BY dept_name
 HAVING AVG(salary) >= ALL 
	(SELECT AVG(salary)
	FROM instructor
	GROUP BY dept_name);

回顾刚刚的几个查询,我们发现内部的查询并没有依赖外部的查询,内部的查询是独立的,即执行顺序为由内到外。接下来我们要将的查询语句将依赖外部的查询,其执行顺序是由外到内。

exists:与in类似,但是不同在于,exists里面的不是独立查询,要依赖外面的查询。

/*这里想找出即在2009年秋季,也在2010年春季开课的课程*/
SELECT course_id
 FROM section AS S
 WHERE semester='Fall' AND YEAR=2009 AND
 EXISTS (SELECT *
	FROM section AS T
	WHERE semester='Spring' AND YEAR=2010 AND
	S.course_id = T.course_id); -- 这一步要依赖外部的S表

接下来给大家一个比较难的例子,去感受一下exists和not exists的具体用法。

/*关系代数中的除法运算:给定两个表A(1,2,3),B(1,2),由于B中的元素
A都有,因此A除B是为真的。说白了,A集合包含B集合,那么A除B就为真
反之,B除A为假,因为B没有包含A集合的全部元素*/
SELECT S.ID,S.name
 FROM student AS S -- 这里先吧student表改名成S
 WHERE NOT EXISTS
	(SELECT *
	FROM course C
	WHERE dept_name='Biology' -- 这里先把生物课程先选出来
	AND NOT EXISTS -- exits的作用可以看成把C中的记录一个一个放到下面判断
		(SELECT *
		FROM takes AS T 
		WHERE S.ID = T.ID -- 到这里筛选出一个学生选的所有课
		AND C.course_id = T.course_id)-- 这里是确定生物课是否都被学生选
		);

在这里插入图片描述

/*可以通过课程数小于等于1找出在2009年没开或者只开一次课的课程*/
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=2009); 

/*需要把子查询结果重新命名,就可以不用加引用都能直接使用*/
SELECT dept_name,avg_salary
 FROM (SELECT dept_name,AVG(salary)-- as avg_salary
	FROM instructor
	GROUP BY dept_name)
	AS dept_avg(dept_name,avg_salary)
 WHERE avg_salary > 42000;

with:创建一个临时表。这个非常常用,可以避免多层查询而导致可读性降低。

 /*with运算符,创建一个临时表,格式with 表名(属性1 , 属性2 ...) as (查询语句)*/
 WITH max_budget(VALUE) AS -- 赋值运算
	(SELECT MAX(budget)
	FROM department  -- 注意格式
	)
 SELECT budget
 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;

这里说一下标量子查询:将查询语句放到select语句中。其实意义本人觉得不大。

/*标量子查询,特点select子句的查询记录一定要等于总select记录的数目
常见的是总select的元素作为select子句中where语句的关键词*/
SELECT dept_name,
	(SELECT COUNT(*) -- select子句的结果作为一个属性
	FROM instructor
	WHERE department.dept_name = instructor.dept_name)
	AS num_instructors
FROM department;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值