数据库系统概念(第六版)———学习笔记

第三章 SQL

查看数据库字符集:

SHOW GLOBAL VARIABLES LIKE '%character_set%';

3.3.1 单关系查询

select语句

1.加入关键字distinct ,去除重复

SELECT DISTINCT dept_name
FROM instructor;

2 . 找到在Comp. Sci. 系且工资>70000的老师名字:
(系名称直接从表内粘,注意空格)

SELECT `name`
FROM instructor
WHERE dept_name = 'Comp. Sci.' AND salary > 70000;

3.3.2 多关系查询

1 . dept_name 属性在instructor,department内都有,选择时必须指定关系表

SELECT `name`,instructor.dept_name,building
FROM instructor,department
WHERE instructor.dept_name = department.dept_name;

2 . 笛卡儿积:结果产生所有组合

SELECT `name`,course_id
FROM instructor,teaches;

3 . where 限制笛卡儿积建立的组合

SELECT `name`,course_id
FROM instructor,teaches
WHERE instructor.ID = teaches.ID;

4 . 自然连接:筛选出在两个关系表中都出现的属性上取值相同的元组对
上面语句可以修改为:

SELECT `name`,course_id
FROM instructor NATURAL JOIN teaches;

5 .列出老师名字和所教授的课程名称
instructor 与 teaches自然连接结果,再与course作笛卡儿积

SELECT `name`,title
FROM instructor NATURAL JOIN teaches,course
WHERE teaches.course_id = course.course_id;

6 .上面语句用 r1 join r2 using(A1,A2):
等价于 t1.A1 = t2.A1 and t1.A2 = t2.A2

SELECT `name`,title
FROM (instructor NATURAL JOIN teaches) JOIN course USING (course_id);

7 .表别名(相关变量)
找出满足下面条件的老师名字,他们比Biology 系老师的最低工资要高:
(where 子句中不能用instructor.salary 这里T、S都是instructor的别名)

SELECT DISTINCT T.`name`
FROM instructor AS T ,instructor AS S
WHERE T.salary > S.salary AND S.dept_name = 'Biology';

3.4.4 排列元组的显示次序

desc(降序)、asc(升序)
按salary降序排列instructor,若薪资相同,再按name升序排列

SELECT *
FROM instructor
ORDER BY salary DESC , `name` ASC;

3.4.5 where子句谓词

(a1,b1) <= (a2,b2) 在a1 <= a2 且 b1 <= b2时为真

SELECT `name`,course_id
FROM instructor,teaches
WHERE (instructor.ID,dept_name) = (teaches.ID,'biology');

上面语句等价于:

SELECT `name`,course_id
FROM instructor,teaches
WHERE instructor.ID = teaches.ID AND dept_name= 'biology';

3.5.1 并运算

union (并),优势:union运算结果自动去除重复
若想保留重复,用 union all
代码中()可省略,但加上便于阅读

(SELECT course_id
FROM section
WHERE semester = 'fall' AND `year` = 2009)
UNION
(SELECT course_id
FROM section
WHERE semester = 'spring' AND `year` = 2010);

3.5.2 交运算

intersect(交),mysql不支持intersect运算,用 inner join 表示交:
找出在2009年秋季和2010年春季学期同时开课的所有课程:
方法一:(intersect, mysql不支持)

(SELECT course_id
FROM section
WHERE semester = 'fall' AND `year` = 2009intersect
(SELECT course_id
FROM section
WHERE semester = 'spring' AND `year` = 2010;

方法二:(INNER JOIN)

SELECT DISTINCT a.course_id FROM
(SELECT course_id
FROM section
WHERE semester = 'fall' AND `year` = 2009) a 
INNER JOIN
(SELECT course_id
FROM section
WHERE semester = 'spring' AND `year` = 2010) b 
ON (a.course_id = b.course_id);

注意:intersect 自动去除重复,intersect all 保留重复
inner join不能自动去除重复,可用select distinct 去除重复结果

方法三:还可以用in测试元组是否是集合中的成员
(where子句嵌套子查询)

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);
							 

3.5.3 差运算

except(差),mysql不支持except运算,用not in 或者 not exists
not exists支持NULL值

找出所有在2009年秋季学期开课,但不在2010年春季学期开课的课程:
方法一:(except, mysql不支持)

(SELECT course_id
FROM section
WHERE semester = 'fall' AND `year` = 2009except
(SELECT course_id
FROM section
WHERE semester = 'spring' AND `year` = 2010);

方法二:mysql用not exists 或者not in:

select course_id
from section sf
where semester = 'Fall' and year = 2009 and not exists
			(select course_id
			from section ss
			where sf.course_id = ss.course_id and ss.semester = 'Spring' and ss.year = 2010
 			);

更简单的代码:(select distinct 删除重复)

select distinct course_id
from section 
where course_id not in 
(
select course_id
from section
where semester = 'Spring' and year= 2010
) 
and semester = 'Fall' and year = 2009;
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);
							 
	 

3.7 聚集函数

3.7.1 基本聚集

count(计数)
1 .找出在2010年春季学期讲授一门课程的老师的总数。
( 不论这个老师讲了几门课,都计为一次)
distinct ID确定唯一的老师ID号:

SELECT COUNT(DISTINCT ID)
FROM teaches
WHERE semester = 'spring' AND `year` = 2010;

2 .(题目难) 找出每个系在2010年春季学期讲授一门课程的老师人数。
同样用 distinct ID来确定唯一的老师ID号,这里teaches关系表需要关联 instructor关系表中的属性(系名称dept_name),用nature join 自然连接筛选出两个关系表中共同的ID,代码:

SELECT dept_name,COUNT(DISTINCT ID) AS instr_count
FROM instructor natural join teaches
WHERE semester = 'spring' and `year` = 2010
GROUP BY dept_name;

3.7.3 having子句

having子句中的谓词在形成分组后才起作用,即在group by子句后
找出教师平均工资超过42000美元的系名字,按系名分组

SELECT dept_name,AVG(salary) as avg_salary
FROM instructor
GROUP BY dept_name
HAVING AVG(salary) > 42000;

3.8.2 集合的比较

1 .至少比一个要大,用 > some表示
找出比biology系某一个老师的工资要高的所有老师名字:
方法一:

SELECT DISTINCT T.`name`
FROM instructor AS T,instructor AS S
WHERE T.salary > S.salary AND S.dept_name = 'biology';

方法二:至少比一个要大,用 > some表示

SELECT `name`
FROM instructor
WHERE salary > SOME (SELECT salary
					FROM instructor
					WHERE dept_name = 'biology');

2 . 比所有的都大,用 > all 表示
找出比biology系每一个老师的工资要高的所有老师名字:

SELECT `name`
FROM instructor
WHERE salary > ALL (SELECT salary
					FROM instructor
					WHERE dept_name = 'biology');

3 . 找出平均工资最高的系
step1: 找出每个系的平均工资
step2: 找出平均工资大于等于所有系平均工资的系(用 >= all)

step1:

SELECT AVG(salary)
FROM instructor
GROUP BY dept_name

step2:

SELECT dept_name
FROM instructor
GROUP BY dept_name
HAVING AVG(salary) >= ALL(SELECT AVG(salary)
					  FROM instructor
					  GROUP BY dept_name);

3.8.5 from子句中的子查询

3.7.3的问题另解:找出教师平均工资超过42000美元的系名字,按系名分组(用select-from-where 嵌套查询):

SELECT dept_name,avg_salary
from (SELECT dept_name,AVG(salary) as avg_salary
	  from instructor
	  GROUP BY dept_name) b 
WHERE avg_salary > 42000;

注意这里 子查询里用 b 作为表别名,必须每个表都有名
select * from (select * from ……) as 别名;

3.8.6 with子句

with子句定义临时关系,这个定义只对包含with子句的查询有效。
1 . 找出具有最大预算值的系:

with max_budget(VALUE) as
	(SELECT max(budget)
	 from department)
SELECT budget
from department,max_budget
where department.budget = max_budget.value;

2 . 找出所有工资总额大于所有系平均工资总额的系:
(难)

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;

3.8.7 标量子查询

子查询可以放在任何位置,只要该子查询只返回包含单个属性的单个元组。
列出所有的系及它们拥有的老师数:

SELECT dept_name,
	  (SELECT COUNT(*)
	   from instructor
	   WHERE department.dept_name = instructor.dept_name)
	   as num_instructors
FROM department;

这里 dept_name , (老师数)num_instructors 都是属性

3.9.1 删除

delete from 关系表 # 删除表中的所有元组,关系表仍然存在
从instructor关系中删除所有这样的教师元组,他们位于Watson大楼的系工作:

DELETE FROM instructor
WHERE dept_name IN(SELECT dept_name
				   FROM department
                   WHERE building = 'Watson');

首先找到Watson大楼的系,再将这些系里的instructor元组全部删除。

3.9.3 更新

给工资超过100000的老师涨3%的工资,其余老师涨5%:
方法一:(update 注意语序)

UPDATE instructor
SET salary = salary * 1.03
WHERE salary > 100000;

UPDATE instructor
SET salary = salary * 1.05
WHERE salary <= 100000;

注意:如果改变UPDATE 语序,工资略低于100000的老师工资将涨8%,更新顺序很重要。

方法二:(case 避免了语序更新问题)

UPDATE instructor
SET salary = case
	       WHEN salary <= 100000 THEN salary * 1.05
		   ELSE salary * 1.03
	 END

3.9 数据库增、删、改总结

1 . 删:delete from 关系表
2 . 增:insert into 关系表
insert into 关系表
values()
3 .改:
update 关系表
set 属性 = XXX

实践习题

3.1 (e~g)

e. 找出2009年秋季开设的每个课程段的选课人数

SELECT course_id,sec_id,COUNT(ID)
FROM takes NATURAL JOIN section
WHERE `year` = 2009 AND semester = 'fall'
GROUP BY course_id,sec_id;

f. 从2009年秋季开设的所有课程中,找出最多的选课人数

SELECT MAX(enrollment)
FROM (SELECT COUNT(ID) as enrollment
			FROM takes NATURAL JOIN section
			WHERE `year` = 2009 AND semester = 'fall'
			GROUP BY course_id,sec_id) b;

g.找出在2009年秋季拥有最多选课人数的课程数

WITH sec_enrollment AS (
			SELECT course_id,sec_id, count(ID) as enrollment
			FROM takes NATURAL JOIN section
			WHERE `year` = 2009 AND semester = 'fall'
			GROUP BY course_id,sec_id)
SELECT course_id,sec_id
FROM sec_enrollment
WHERE enrollment = (SELECT max(enrollment) from sec_enrollment);

你可能感兴趣的:(数据库系统概念(第六版)———学习笔记)