《数据库系统概念(原书第 6 版)》读书笔记。
第一部分:2~6 章,详细讲解了关系型数据库。
第三章 SQL
3、4、5 章将会讲解使用最为广泛的查询语言 SQL,讲解的目的并不是提供一个完整的 SQL 用户手册,而是介绍 SQL 的基本结构和概念。
SQL 最早叫 Squeal,由 IBM 开发,后来名称更改为 SQL(Structured Query Language)。
1986 年美国国家标准化组织(ANSI)和国际标准化组织(ISO)发布了 SQL 标准:SQL—86。现在 SQL 最新的版本是 SQL:2008。
截止到 2022 年 9 月 29 日,SQL 最新的版本为 SQL: 2016.
SQL 语言标准由以下几个部分组成:
SQL 是一种标准,MySQL、ORACLE、PostgreSQL、SQLServer 等是对标准的实现,且在标准之上添加了一些自有的特征。SQL 和他们的关系类似于 ES 规范和各家浏览器对 ES 规范的实现。
SQL 标准支持多种固有类型,包括:
注意:
Avi
时,该字符串会追加 7 个空格来使其达到 10 个字符的长度。varchar 类型则不会这样做。Avi
时,两者是否相等取决于数据库管理系统的实现,因此始终建议使用 varchar 类型。数据库模式:数据库的逻辑设计; 这里讲的是设计关系(表)时一些常用的命令。
使用 create table 定义 SQL 关系(表)。
SQL-- 通用形式
create table r (
A1 D1,
A2 D2,
...,
An Dn,
<完整性约束>,
...,
<完整性约束>,
);
-- 示例
create table department (
dept_name varchar(20),
building varchar(15),
budget numeric(12, 2),
primary key (dept_name)
);
常见的完整性约束命令:
insert 命令将数据加载到关系中:
SQL-- instructor 关系中插入一条数据
insert into instructor
values (10211, 'Smith', 'Biology', 66000);
delete 命令用于从关系中删除元组:
SQL-- 从 student 关系中删除所有元组
delete from student;
drop table 用于从数据库中删除关系。该命令也会将关系中的所有元组删除。
SQL-- 删除表 r
drop table r;
SQL-- 可以包括重复数据
select A1, A2,.., An from R;
-- 去除重复
select distinct A1, A2,.., An from R;
-- 显示的不去除重复
select all A1, A2, ..., An from R;
-- select 子句可以含有 + - * / 运算符的算术表达式;运算对象可以是常数或元组的属性。
select A1, A2, ..., A3 * 1.1 from R;
-- where 子句可以包括逻辑连词 and, or 和 not
-- 逻辑连词的运算对象可以使包含比较运算符的 <, <=, >, >=, = 和 <> 的表达式
select A1, A2, ... An from R where A1=V1 and A2=V2;
涉及多个关系的 SQL 查询中,各子句作用:
*
可表示“所有的属性”。理解查询所代表的的运算:
上述步骤的顺序有助于理解 SQL 查询的结果应该是怎样的,而不是此结果怎样被执行的。
SQL 的实际实现中不会执行这种形式的查询,它尽可能只产生满足 where 子句谓词的笛卡尔积元素,以此优化执行。
笛卡尔积:
例如:
SQL-- 笛卡尔积
select name, course_id
from instructor,teaches
where instructor. ID = teaches.ID;
-- 自然连接
select name, course_id
from instructor natural join teaches;
3.4.1 更名运算
SQLselect T.name, S.course_id
from instructor as T, teaches as S
where T.ID = S.ID;
3.4.2 字符串运算
3.4.3 select 子句中的属性说明
*
表示所有属性:
sqlselect instructor.*
from instructor,teaches
where instructor.ID = teaches.ID;
3.4.4 排列元组的显示次序
sqlselect
from instructor
order by salary desc, name asc;
3.4.5 where 子句谓词
使用比较运算符 between 可以简化 where 子句。
sql-- 使用前
select name
from instructor
where salary <=100000 and salary >=90000;
-- 使用后
select name
from instructor
where salary between 90000 and 100000;
在元组上使用比较运算符,那么会按照字典顺序进行比较。
sqlselect name, course_id
from instructor, teaches
where instructor.ID= teaches.ID and dept_name = "Biology";
-- 可以重写为
select name, course_id
from instructor, teaches
where (instructor.ID, dept_name) = (teaches.ID, 'Biology');
SQL 作用在关系上的 union、intersect 和 except 运算对应于数学集合论中的并集 (∪)、交集 (∩) 和差集 (−) 运算。
3.5.1 并运算
sql(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 交运算
3.5.3 差运算
空值运算规则:
如果算数表达式(+-*/)的任意输入为空,则该算数表达式结果为空 涉及空值的任何比较运算的结果视为 unknown(既不是谓词 is null, 也不是 is not null),是 true 和 false 之外的第三个逻辑值 扩展到 unknown 的布尔运算:
注意:
select distinct 会去除重复元组。在该过程中,需要比较两个元组的对应的属性值。如果两个值都是非空并且值相等,或者都为空,那么它们是相同的。
但是这与谓词对待空值的方式不同,谓词中 null = null 会返回 unknown,而不是 true。
以值的一个集合(集或多重集)为输入,返回单个值。
3.7.1 基本聚集
sql-- 找出 Comp. Sci. 系教师的平均工资
-- 计算平均值需要保留重复元祖
select avg(salary)
from instructor
where department = 'Comp. Sci.';
-- 找出在 2010 年春季学期讲授一门课程的教师总数
-- distinct 表示去掉重复元祖
select count(distinct ID)
from teaches
where semester = 'Spring' and year = 2010
3.7.2 分组聚集
目前为止的所有计算都是在表的所有数据或匹配特定的 WHERE 子句的数据上进行的。group by 子句可以将元祖进行分组。
sqlselect dept_name, avg(salary) as avg_salary
from instructor
group by dept_name;
需要注意的是:select 子句中没有使用聚集函数的属性,必须出现在 group by 子句中!
sql-- 错误示例!!!
select dept_name, ID, avg(salary)
from instructor
group by dept_name;
结果(错误的):
dept_name | ID | avg(salary) |
---|---|---|
Biology | 76766 | 72000.000000 |
Comp. Sci. | 10101 | 77333.333333 |
Elec. Eng. | 98345 | 80000.000000 |
Finance | 12121 | 85000.000000 |
History | 32343 | 61000.000000 |
Music | 15151 | 40000.000000 |
Physics | 22222 | 91000.000000 |
在一个特定分组中(dept_name)的每位老师都有一个 ID,因为每个分组只能输出一个元祖,所以无法确定选哪个 ID 作为输出结果。
sql-- 正确示例
select dept_name, ID, avg(salary)
from instructor
group by dept_name, ID;
结果(正确的):
dept_name | ID | avg(salary) |
---|---|---|
Biology | 76766 | 72000.000000 |
Comp. Sci. | 10101 | 65000.000000 |
Comp. Sci. | 45565 | 75000.000000 |
Comp. Sci. | 83821 | 92000.000000 |
Elec. Eng. | 98345 | 80000.000000 |
Finance | 12121 | 90000.000000 |
Finance | 76543 | 80000.000000 |
History | 32343 | 60000.000000 |
History | 58583 | 62000.000000 |
Music | 15151 | 40000.000000 |
Physics | 22222 | 95000.000000 |
Physics | 33456 | 87000.000000 |
3.7.3 having 子句
sqlselect dept_name, avg(salary) as avg_salary
from instructor
group by dept_name
having avg(salary) > 42000;
3.7.4 对空值和布尔值的聚集
聚集函数根据以下原则处理空值:除了 count(*) 外所有的聚集函数都忽略输入集合中的空值。 由于空值被忽略,有可能造成参加函数运算的输入值集合为空集。
3.8.1 集合成员资格 3.8.2 集合的比较 3.8.3 空关系测试 3.8.4 重复元组存在性测试 3.8.5 from 子句中的子查询 3.8.6 with 子句 3.8.7 标量子查询
3.9.1 删除
sqldelete from r where P;
3.9.2 插入
sqlinsert into r values (v1, v2, ..., vn);
-- 先执行完 select 子句,然后执行 insert 子句
INSERT INTO
r (
SELECT
(A1, A2,..., An)
FROM
r
WHERE
P
);
3.9.3 更新
sqlUPDATE
r
SET
A1 = v1
WHERE
P;
-- case 结构
CASE
WHEN pred1 THEN res1
WHEN pred2 THEN res2...
WHEN predn THEN resn
ELSE res0
END
-- 更新每个 student 的 tot_cred 属性值设为该生成功 学完的课程的总学分。
-- grade 既不是 F 也不是 null,则表明成功学完了该门课程
UPDATE
student S
SET
tot_cred = (
SELECT
sum(credits)
FROM
takes NATURAL
JOIN course
WHERE
S.ID = takes.ID
AND takes.grade <> 'F'
AND takes.grode IS NOT NULL
);
-- 如果学生没有成功完成任何一门课程,则 tot_cred 被设置为 null。
-- 如果希望将这样的属性值设为 0,那么需要使用另一条 update
-- 上述 sql 可改写为
UPDATE
student S
SET
tot_cred = (
SELECT
CASE
WHEN sum(credits) IS NOT NULL THEN sum(credits)
ELSE 0
END
FROM
takes NATURAL
JOIN course
WHERE
S.ID = takes.ID
AND takes.grade <> 'F'
AND takes.grode IS NOT NULL
);
略
本文作者:青波
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!