数据库1-5章复习
数据库1-5章复习
面对这种没有明确题型的随堂测验,最稳妥的策略是“抓大放小,理清主干,主攻查询”。数据库这门课的特点是:概念多但逻辑性强,SQL语法碎但套路固定。
通常这类测验的题型无外乎三种:
- 概念理解题(选择、判断、填空、简答):考查第1、2章的基本概念,以及各章中的理论部分(如视图的作用、事务的特性等)。
- 读码/写码题(核心大头):给出英文/中文需求,让你写出关系代数(第2章)或SQL语句(第3、4章);或者给你一段SQL,问你输出什么。
- 应用机制题:结合第4、5章,考查完整性约束怎么写、触发器怎么工作、JDBC防止SQL注入的原理等。
不用慌,我为你梳理了一份核心考点大纲和SQL复习套路,照着这个框架复习,效率会高很多。
📚 核心考点大纲(划重点版)
第1章:引言 (Introduction) - 纯概念,重理解
- 文件系统 vs 数据库系统:为什么要有数据库?(解决数据冗余、不一致、数据孤岛、并发异常、安全性问题)。
- 数据抽象的三个层次:物理层(怎么存)、逻辑层(存什么,有什么联系)、视图层(给特定用户看什么)。了解“物理数据独立性”。
- 模式 (Schema) 与实例 (Instance):模式是结构(不常变),实例是某一时刻的数据(常变)。类似于编程语言中的类型与变量。
- 数据库语言:DDL(数据定义语言,建表/约束)、DML(数据操纵语言,增删改查)。
第2章:关系模型介绍 (Relational Model) - 必考基础与关系代数
- 基本概念:关系(表)、元组(行)、属性(列)、域(Domain,必须是原子的)。
- 键 (Keys) 的辨析(绝对重点):
- 超码 (Superkey):能唯一标识元组的属性集。
- 候选码 (Candidate key):最小的超码。
- 主码 (Primary key):被选中用来标识元组的候选码。
- 外码 (Foreign key):用于引用完整性,参照另一张表的主码。
- 关系代数 (Relational Algebra)(必考写表达式):
- 基本操作:选择 $\sigma$ (where)、投影 $\Pi$ (select)、笛卡尔积 $\times$、并 $\cup$、差 $-$、更名 $\rho$。
- 附加操作:集合交 $\cap$、自然连接 $\bowtie$、赋值 $\leftarrow$。
第3章:SQL 介绍 (Introduction to SQL) - 重中之重,占分最高
- DDL基础:
create table的基本语法,主键、外键、not null的声明。 - 基本查询结构:
select ... from ... where ...(注意select distinct去重)。 - 字符串操作:
like的通配符(%匹配任意子串,_匹配单个字符),转义escape。 - 集合操作:
union,intersect,except(默认去重,带all不去重)。 - 空值 (Null) 逻辑:任何涉及 Null 的算术运算结果为 Null;比较运算结果为
unknown;where子句中只接受true(false和unknown都被过滤)。使用is null判断。 - 聚集函数与分组(极易出题):
count,sum,avg,max,min。- 关键规则:
select语句中没有被聚集的属性,必须出现在group by子句中! where(分组前过滤) vshaving(分组后过滤)。
- 嵌套子查询(难点):
- 集合成员:
in,not in。 - 集合比较:
> some(大于其中至少一个),> all(大于所有)。 - 空关系测试:
exists,not exists(常用于表达“全部包含”这类复杂的逻辑)。
- 集合成员:
- 数据库修改:
insert,delete,update(注意update中使用case when ... then ...避免顺序问题的考点)。
第4章:中级 SQL (Intermediate SQL) - 进阶查询与数据库特性
- 连接 (Join) 表达式(必考):
- 内连接:
natural join,join ... using(...),join ... on ...。了解natural join的危险性(同名但不相关的列被错误匹配)。 - 外连接:
left outer join,right outer join,full outer join(保留未匹配的元组,用 Null 填充)。
- 内连接:
- 视图 (Views):
- 作用:简化查询、安全性(隐藏数据)。
- 物化视图 (Materialized Views) 的概念。
- 视图更新的限制:通常只能在简单的视图上进行
insert/update/delete(单表、无聚集、无 distinct)。
- 事务 (Transactions):
commit(提交)与rollback(回滚),保证原子性。 - 完整性约束:
not null,unique,check(谓词),以及外键的级联操作on delete cascade/set null。 - 授权 (Authorization):
grant <权限> on <表/视图> to <用户/角色>和revoke命令。
第5章:高级 SQL (Advanced SQL, 仅限 5.1 - 5.3) - 偏向机制与应用
- 5.1 编程语言访问 (JDBC/ODBC):
- 为什么需要?(SQL不是图灵完备的,无法做UI等)。
- 预备语句 (PreparedStatement) 的作用:提高效率,防止 SQL 注入 (SQL Injection)(必考概念!千万不要用字符串拼接拼SQL)。
- 元数据 (Metadata) 的作用。
- 5.2 函数与过程 (Functions and Procedures):
- 了解如何使用
create function和create procedure将业务逻辑写在数据库里。参数类型 (in,out)。
- 了解如何使用
- 5.3 触发器 (Triggers):
- 组成:事件 (insert/update/delete) + 条件 (when) + 动作 (begin…end)。
referencing new row as/old row as的用法。- 何时不该用触发器?(现在很多功能如图2、复制、统计表已经被物化视图和内置复制机制取代,触发器容易导致级联错误和意外执行)。
💡 针对“SQL语法太碎”的复习套路
不要死记硬背SQL,在脑子里建立一个“SQL执行顺序”的模型。当你写SQL或者读SQL时,按照数据库的执行逻辑来想,就不会乱:
FROM:先找数据源。我要查的数据在哪几张表里?需不需要JOIN?WHERE:过滤行。在连好的大表里,哪些行是我不要的?(注意:这里不能用聚集函数)。GROUP BY:分组。把剩下的行按什么特征分类?HAVING:过滤组。分完组之后,哪些组是我不要的?(这里通常配合sum,count等聚集函数)。SELECT:提取列。最后我要展示哪些列?计算什么表达式?ORDER BY:排序。最后结果按什么顺序输出?
举个应试例子: 题目:找出 2018年春季学期,教授超过一门课的教师ID和姓名。
- 思考步骤:
- 涉及表 (
FROM):教师表 (instructor) 和 授课表 (teaches),因为需要姓名和授课时间。 - 怎么连:
instructor natural join teaches - 初步过滤 (
WHERE):year = 2018 and semester = 'Spring' - 怎么分组 (
GROUP BY):按老师分group by instructor.ID, name - 分组后过滤 (
HAVING):教的课超过一门having count(course_id) > 1 - 展示结果 (
SELECT):select ID, name
- 涉及表 (
🚀 最后两天的突击策略
- 翻课本/PPT的例题:把你PDF里的所有SQL例题看懂。教授出题大概率就是把课件上的例题改一改表名或者条件。特别注意大学模型(
student,instructor,course,takes,teaches)的表结构,这是全书的基石。 - 手写代数与SQL:拿一张白纸,挡住答案,自己手写几道。特别是关系代数,由于只能用纯文本符号,很容易写错角标或括号;多表查询一定要想清楚关联条件。
- 不要钻牛角尖:第5章的代码(比如JDBC具体的Java代码怎么写)一般不会让你默写,主要是考概念(比如为什么要用PreparedStatement)。重点拿分的还是第3章和第4章的查询语句。
深呼吸,按照大纲把知识点过一遍,理清逻辑,测验没问题的!祝你好运!
没问题!第一章虽然全是概念,但它是整个数据库体系的“世界观”。考试中这部分通常以选择题、判断题、填空题或简答题的形式出现。
我们结合你课本上的例子(大学模型和银行模型),把这四个核心知识点掰开揉碎,帮你真正理解:
1. 文件系统 vs 数据库系统:为什么要有数据库?
考点:理解早期文件处理系统的7大弊端(简答题常客,也常在选择题中通过案例让你判断属于哪种弊端)。
在数据库出现之前,人们把数据存在操作系统的普通文件里(比如txt、csv),这会导致以下致命问题,而数据库系统 (DBMS) 完美解决了它们:
- 数据的冗余和不一致性 (Data redundancy and inconsistency)
- 概念:同一份数据在多个文件中重复存储(冗余),一旦修改没同步,就会导致数据冲突(不一致)。
- 课本例子:一个学生同时辅修音乐和数学,他的地址可能同时存在音乐系和数学系的文件里。如果他搬家了,只改了音乐系的文件,数学系的文件没改,系统里就有两个不同的地址了。
- 数据访问困难 (Difficulty in accessing data)
- 概念:想查点新东西,必须让程序员新写一个程序。
- 课本例子:你想查“邮编是10086的所有学生”,文件系统里没有现成的程序,你只能人工找,或者求程序员现写一个代码,极不方便。
- 数据孤岛 (Data isolation)
- 概念:数据散落在不同格式的文件里,想把它们联合起来查询非常困难。
- 完整性问题 (Integrity problem)
- 概念:数据必须满足某些业务规则(约束),文件系统很难强制执行。
- 课本例子:银行账户余额不能小于0。在文件系统里,你必须在每段取钱的代码里手写判断逻辑;但在数据库里,你可以直接声明一个约束(
check balance >= 0),数据库会自动把关。
- 原子性问题 (Atomicity problem) —— 重点!
- 概念:一个操作要么全做,要么全都不做,不能停在中间状态。
- 课本例子:A账户给B账户转账500元,A扣了500,突然系统断电崩溃了,B还没来得及加500。钱凭空消失了!数据库能保证这种事不发生(故障恢复)。
- 并发访问异常 (Concurrent-access anomaly) —— 重点!
- 概念:多个用户同时操作同一条数据,结果算错了。
- 课本例子:账户里有10000元。职员甲取500,职员乙取100。两人同时读取到10000,甲算出9500写回去,乙算出9900写回去。最后账户变成了9900,银行亏了400。数据库有并发控制机制来解决。
- 安全性问题 (Security problem)
- 概念:不是所有人都能看所有数据。
- 课本例子:工资管理员能看财务信息,但不能看学生成绩。
2. 数据抽象的三个层次(Levels of Abstraction)
考点:区分物理层、逻辑层、视图层,深刻理解“物理数据独立性”。
为了让普通用户能轻松使用数据库,而不必去学底层硬盘的读写原理,数据库把数据分成了三个抽象层次:
- 物理层 (Physical level):最低层。
- 描述:数据实际上是怎么存储在硬盘上的(涉及底层的数据结构、字节、索引、B+树等)。这是数据库引擎开发者关心的。
- 逻辑层 (Logical level):中间层。
- 描述:数据库中存储了什么数据,以及这些数据之间有什么联系。
- 受众:数据库管理员 (DBA) 和程序员。例如,在这里我们定义
instructor表有ID,name,salary几个字段。
- 视图层 (View level):最高层。
- 描述:只描述整个数据库的某一部分,隐藏了其他不相关或机密的数据。
- 受众:终端用户。例如,教务处注册选课的系统(一个视图)只能看到学生和课程,看不到老师的工资。
💡 核心考点:物理数据独立性 (Physical Data Independence)
- 定义:应用程序依赖于逻辑模式,而不依赖于物理模式。
- 大白话:不管底层物理层怎么变(比如把数据从机械硬盘迁移到固态硬盘,或者给表加了一个新索引加快查询速度),逻辑层的表结构没变,所以上面写的SQL应用程序一行代码都不需要改。
3. 模式 (Schema) 与实例 (Instance)
考点:类比编程语言,区分静态的结构和动态的数据。
- 模式 (Schema):
- 定义:数据库的总体逻辑结构/设计。
- 特点:一旦设计好,极少改变。
- 编程类比:就像C/Java里的变量声明或类的定义(
int a;或class Student { ... })。
- 实例 (Instance):
- 定义:在特定时刻,数据库中实际存储的数据集合(即表里填进去的一行行数据快照)。
- 特点:随着增删改查,时刻都在变化。
- 编程类比:就像程序运行时,某个变量在某一时刻的具体值(
a = 5;)。
4. 数据库语言 (Database Languages)
考点:区分 DDL 和 DML 的作用,理解“声明式”。
数据库系统提供两种主要的语言(通常统合在 SQL 中)来操作上面的模式和实例:
- 数据定义语言 (DDL - Data Definition Language):
- 作用:用来定义数据库的模式 (Schema),也就是建表、改表结构、加约束。
- 输出:DDL 执行后,会把结果生成元数据(关于数据的数据)存放在数据字典 (Data Dictionary) 中。
- 代表操作:
CREATE TABLE,DROP,ALTER。约束如NOT NULL(非空),PRIMARY KEY(主键)。
- 数据操纵语言 (DML - Data Manipulation Language):
- 作用:用来操作数据库中的实例 (Instance),也就是对数据进行增、删、改、查。
- 代表操作:
SELECT(查),INSERT(增),UPDATE(改),DELETE(删)。 - 分类(易考概念):
- 过程化 DML (Procedural):用户需要指定要什么数据,还要指定怎么一步步去获取(像用C语言写一个for循环去找数据)。
- 声明式 DML (Declarative / Non-procedural):用户只需要说明“我要什么数据”,不需要管底层怎么找。SQL 查询就是声明式的! 系统内部的“查询优化器”会自动寻找最高效的获取路径。
复习小测(检验一下):
- 学生搬家导致三个系统地址不一致,属于文件系统的什么弊端?(答:数据冗余和不一致性)
- 数据库底层从机械硬盘换成SSD,我的SQL查询代码需要重写吗?这体现了什么性质?(答:不需要,体现了物理数据独立性)
CREATE TABLE命令属于DDL还是DML?(答:DDL)- SQL查询语言是过程化的还是声明式的?(答:声明式的)
理清了第一章的这些基本概念,你的数据库基础框架就搭好了!接下来要不要一起顺一顺第二章(关系代数与各种键的区分)?
第二章是整个关系数据库的灵魂!SQL语句的底层逻辑全是关系代数。考试中,这一章要么出在选择判断题里考“键”的辨析,要么就是大题:“请用关系代数写出下列查询”。
我们把这块“硬骨头”啃下来:
1. 基本概念:数学黑话翻译
考点:关系是“集合”,所以无序且不能有重复行;域必须是“原子的”。
数据库学者喜欢用数学名词,我们把它翻译成大白话:
- 关系 (Relation) = 表 (Table)
- 元组 (Tuple) = 行 (Row / Record)。表里的一条记录。
- 属性 (Attribute) = 列 (Column / Field)。表的一个字段。
- 关系实例 (Relation Instance) = 某一个时刻表里装的具体数据。
- 域 (Domain) = 某个属性允许取值的集合(比如整数、字符串)。
- 🚨 必考点:关系模型要求域必须是原子的 (Atomic)!意思就是不可再分。比如“电话号码”这个属性,里面不能存一个列表
[138xxx, 139xxx],只能存一个单一的值。
- 🚨 必考点:关系模型要求域必须是原子的 (Atomic)!意思就是不可再分。比如“电话号码”这个属性,里面不能存一个列表
2. 键 (Keys) 的辨析(绝对重点,必考套娃逻辑)
考点:给你几个属性集,让你判断哪个是超码、候选码。一定要记住它们的“包含关系”。
假设有一张学生表 Student(学号, 身份证号, 姓名, 年龄)。
- 超码 (Superkey):
- 定义:只要能唯一标识一行元组的属性集合,都是超码。它允许有“废话”(多余属性)。
- 例子:
{学号}是超码;{学号, 姓名}也是超码;{身份证号, 年龄}也是超码。只要带上学号或身份证号,就能唯一确定一个人。
- 候选码 (Candidate key):
- 定义:最小的超码。也就是超码里把“废话”全删掉,多一个嫌胖,少一个不行。
- 例子:
{学号}是候选码,{身份证号}也是候选码。但{学号, 姓名}不是候选码,因为去掉“姓名”后,剩下的{学号}依然能唯一标识。
- 主码 (Primary key):
- 定义:数据库设计师从多个“候选码”中选定出场的一个。通常在表结构设计中底下画一条实线下划线(如 $\underline{ID}$)。
- 例子:设计师一拍大腿,决定用
{学号}当主码。
- 外码 (Foreign key):
- 定义:本表的某个属性,它不是本表的主码,但它是另一张表的主码。用于维持引用完整性 (Referential Integrity)。
- 例子:
教师表(ID, 姓名, 所在系),系表(系名, 预算)。教师表里的“所在系”就是外码,引用了系表的主码“系名”。意思是:老师所在的系,必须在系表里真实存在。
💡 做题口诀:主码 $\subseteq$ 候选码 $\subseteq$ 超码。候选码是极简版的超码。
3. 关系代数 (Relational Algebra) - 必考大题
考点:给你一句话,让你画出这些希腊字母的组合。把它们直接当成 SQL 语句的底层函数来记!
① 基本操作(大写六剑客)
- 选择 $\sigma$ (Sigma) —— 对应 SQL 的
WHERE(过滤行)- 用法:$\sigma_{条件}(表名)$
- 例子:找出物理系的老师 $\rightarrow \sigma_{dept_name=”Physics”}(instructor)$
- 投影 $\Pi$ (Pi) —— 对应 SQL 的
SELECT(过滤列)- 用法:$\Pi_{列名1, 列名2}(表名)$
- 例子:只看老师的名字和工资 $\rightarrow \Pi_{name, salary}(instructor)$
- 🚨 易错考点:关系代数里的 $\Pi$ 会自动去重!(因为关系是集合,集合里不能有重复元素),这和 SQL 的
SELECT(默认不去重)不一样。
- 笛卡尔积 $\times$ (Cross Product) —— 对应 SQL 的
FROM A, B(无脑硬组CP)- 用法:$A \times B$
- 效果:A表有3行,B表有4行,乘出来就是 $3 \times 4 = 12$ 行。把所有可能全配对。
- 并 $\cup$ (Union) —— 对应 SQL 的
UNION- 用法:$A \cup B$ (把A和B的行拼在一起)
- 前提:相容性(两张表的列数必须一样,对应列的数据类型必须一样)。自动去重。
- 差 $-$ (Set Difference) —— 对应 SQL 的
EXCEPT/MINUS- 用法:$A - B$ (在A里,但不在B里)
- 例子:2017秋季开的课 $-$ 2018春季开的课 = 只有17秋开过,18春没开的课。
- 更名 $\rho$ (Rho) —— 对应 SQL 的
AS(起别名)- 用法:$\rho_{新表名}(原表)$ 或 $\rho_{新表名(新列1, 新列2)}(原表)$
- 作用:当你想把一张表和它自己做连接时(自连接),比如“找出比爱因斯坦工资高的老师”,必须用 $\rho$ 复制出一个假分身。
② 附加操作(方便你写表达式的组合技)
- 集合交 $\cap$ (Intersection) —— 对应 SQL 的
INTERSECT- 用法:$A \cap B$ (既在A里,又在B里)
- 其实它是推导出来的:$A \cap B = A - (A - B)$。
- 自然连接 $\bowtie$ (Natural Join) —— 对应 SQL 的
NATURAL JOIN- 用法:$A \bowtie B$
- 极其重要:它是 $\times$(笛卡尔积) + $\sigma$(挑出同名列相等的行) + $\Pi$(删掉重复列)的完美结合体!
- 效果:系统会自动去找A表和B表里名字一样的列,让它们的值相等,拼成一张大表。
- 例子:$\Pi_{name, course_id} (student \bowtie takes)$ $\rightarrow$ 查出所有选了课的学生名字和课程号。(底层自动通过学号
ID把学生表和选课表连起来了)。
- 赋值 $\leftarrow$ (Assignment) —— 像写代码一样定义中间变量
- 用法:$临时表 \leftarrow 关系代数表达式$
- 作用:如果一道大题非常长,不要写一长串反人类的嵌套,可以用 $\leftarrow$ 分步写,卷面清晰,老师给分也爽。
- 例子: $Physics \leftarrow \sigma_{dept_name=”Physics”}(instructor)$ $Music \leftarrow \sigma_{dept_name=”Music”}(instructor)$ $Result \leftarrow Physics \cup Music$
📝 实战组合拳(考试怎么写?)
经典真题:找出讲授了“CS-101”这门课的所有教师的名字。 (涉及表:instructor(ID, name, dept_name, salary) 和 teaches(ID, course_id, sec_id, semester, year))
- 思路拆解:
- 先把教师表和授课表连起来,才能同时看到名字和课号:$instructor \bowtie teaches$
- 从连好的大表里,挑出课号是”CS-101”的行(用选择 $\sigma$):$\sigma_{course_id=”CS-101”}(…)$
- 最后只展示名字这一列(用投影 $\Pi$):$\Pi_{name}(…)$
- 满分答案: $\Pi_{name} (\sigma_{course_id=”CS-101”} (instructor \bowtie teaches))$
复习小测(检验一下):
- ${学号, 姓名}$ 可以唯一确定一个学生,那么它是候选码吗?(答:大概率不是,因为它包含多余属性“姓名”,它是超码。除非没有学号,单靠姓名也能唯一确定一个人(现实不可能),它才是最小的。)
- 外码的值可以为空 (Null) 吗?(答:可以!只要它不属于本表的主码。比如一个员工暂时没分部门,他的
dept_name可以是 null。) - $\Pi_{dept_name}(instructor)$ 查出物理系3人、计算机系2人。最终输出几行?(答:2行。关系代数的 $\Pi$ 必去重!)
把关系代数里的符号和 SQL 的 SELECT / FROM / WHERE 对应起来,第二章的图谱你就拿捏了!顺着这个逻辑,我们要不要进军最核心的第3/4章:SQL实战?
到了第三章,纯实战、纯敲代码的部分来了!这章在考试中的分值绝对是最高的,通常会给你几张表(比如经典的 student, course, instructor, takes, teaches),然后出 5-8 道大题让你手写 SQL。
不要怕语法碎,我们把这些语法按“套路”分类,帮你精准踩在采分点上:
1. DDL基础:建表与打地基
考点:默写 CREATE TABLE 语句,不要漏掉数据类型和约束。
满分模板:
1
2
3
4
5
6
7
8
create table instructor (
ID char(5), -- 定长字符串
name varchar(20) not null,-- 变长字符串,非空约束
dept_name varchar(20),
salary numeric(8,2), -- 总共8位,包含2位小数
primary key (ID), -- 声明主码
foreign key (dept_name) references department(dept_name) -- 声明外码
);
2. 基本查询与字符串操作
考点:去重 (distinct) 和模糊匹配 (like) 的细节。
- 去重陷阱:关系代数默认去重,但 SQL 的
SELECT默认不去重! 想要去重必须加上distinct。select dept_name from instructor;(不去重)select distinct dept_name from instructor;(去重)
- 字符串匹配 (
like):%:匹配0个或多个字符。(例如:'%dar%'包含 dar)。_:匹配恰好1个字符。(例如:'_ _ _'恰好三个字符)。- 转义考点:如果我想查名字里真有百分号
%的人怎么办?用escape!where name like '100\%' escape '\'(意思是\后面的%是普通的字符,不是通配符)。
3. 集合操作(并、交、差)
考点:记住它们和 SELECT 的脾气是反着的。
union(并),intersect(交),except(差)。- 反常识考点:集合操作默认自动去重!(这和数学里的集合定义一致)。如果你想保留重复的行,必须加上
all:union all,intersect all,except all。
4. 空值 (Null) 的“三值逻辑”(极易出选择题)
考点:遇到 Null,一切都变得不确定 (unknown)。
- 算术运算:任何数
+ - * /Null = Null。(5 + Null = Null) - 比较运算:任何数
> < =Null = unknown。(5 > Null = unknown) - 逻辑运算(真假判断):把
unknown当成“我不知道”。true AND unknown= unknownfalse AND unknown= false (只要有一个错,就是错)true OR unknown= true (只要有一个对,就是对)NOT unknown= unknown
- WHERE 子句的冷酷无情:
WHERE只要遇到计算结果为false或者unknown的行,一律过滤掉!只有明确为true才能留下。 - 判断空值:千万不能写
salary = null,必须写salary is null或salary is not null。
5. 聚集函数与分组(⭐⭐🌟 必考写代码!)
考点:GROUP BY 的“连坐规则”和 HAVING 的执行时机。
五个神兵:count(计数), sum(求和), avg(平均), max(最大), min(最小)。
🚨 数据库铁律(默念三遍): “SELECT 语句中,如果没有被聚集函数包裹的属性,必须原封不动地出现在 GROUP BY 子句中!”
- 错误示范:
select dept_name, ID, avg(salary) from instructor group by dept_name;(报错!按系分组后,一个系有多个老师,你让我输出哪个ID?数据库做不到啊!) - 正确示范:
select dept_name, avg(salary) from instructor group by dept_name;
💡 WHERE vs HAVING:
WHERE:在分组之前起作用,过滤的是一行行的数据。HAVING:在分组之后起作用,过滤的是一组组的数据。(HAVING后面通常跟着聚集函数)。- 实战:找出平均工资大于42000的系名。
1 2 3 4
select dept_name, avg(salary) from instructor group by dept_name having avg(salary) > 42000;
6. 嵌套子查询(高分分水岭)
考点:把一个 SELECT 的结果,当成另一个 SELECT 的条件。
- 集合成员 (
in/not in):- 判断元素在不在子查询的结果集里。
- 例子:找出同时在17秋和18春开课的课程:
where course_id in (select ...)
- 集合比较 (
> some/> all):> some:大于其中随便哪一个(即大于最小值)。> all:大于里面的所有(即大于最大值)。- 等价替换:
= some就是in;但<> some不等于not in(<> all才是not in)。
- 空关系测试 (
exists/not exists):exists判断子查询里是不是有数据(有返回 true,空返回 false)。- 超级大招(相关子查询):当你在子查询的
WHERE里,用到了外层查询的表名,这就叫相关子查询(Correlated Subquery)。它像一个for循环,外层每过一行,内层就跑一遍。
7. 数据库修改(DML 避坑指南)
考点:UPDATE 顺序导致的逻辑漏洞。
- 增:
insert into course values ('CS-437', 'DB', 'Comp. Sci.', 4); - 删:
delete from instructor where salary < 30000; - 改 (
UPDATE的连环计):- 需求:工资超10万的涨3%,10万以下的涨5%。
- 错误写法(先后顺序写两句):
1 2
update instructor set salary = salary * 1.05 where salary <= 100000; update instructor set salary = salary * 1.03 where salary > 100000;
坑在哪里? 如果一个人原本工资 98000,执行第一句后涨到 102900。执行第二句时,他被判定为 >100000,又被涨了 3%!
- 满分写法 (
CASE WHEN神器):同时判断,绝不误伤。1 2 3 4 5
update instructor set salary = case when salary <= 100000 then salary * 1.05 else salary * 1.03 end;
考前小测(检验一下):
- 我想查
student表,找出tot_cred是空值的学生,能写where tot_cred = null吗?(答:不能,必须写is null) select dept_name, count(ID) from instructor缺了什么子句?(答:缺了group by dept_name,非聚集列必须在group by里)- 我要查“找出名字不是 Mozart 也不是 Einstein 的老师”,用集合成员怎么写?(答:
where name not in ('Mozart', 'Einstein'))
拿下第三章,考试卷面一半以上的分数你就稳稳拿在手里了!想不想顺势把第四章(JOIN的多种变体与视图、事务)的精华也串一遍?
第四章是 SQL 的“进阶与填坑”指南。如果说第三章教你怎么把数据查出来,第四章就是教你怎么连表不出错、怎么保护数据、怎么管理权限。
这一章的考点非常明确,特别是“Natural Join 的夺命连环坑”和“视图能不能更新”,几乎是每张卷子的必考题。我们来逐一击破:
1. 连接 (Join) 表达式 —— 必考的“连表刺客”
考点:辨析内连接和外连接的区别;准确识别 natural join 的危险性。
① 内连接 (Inner Join) 的三种写法
内连接只保留两张表都能匹配上的行。
join ... on ...:最安全的写法。student join takes on student.ID = takes.IDjoin ... using(...):指定按哪些同名列连接。student join takes using(ID)- 致命诱惑:
natural join(自然连接)- 原理:系统会自动寻找两张表里所有“同名”的列,并且要求它们的值必须相等。
- 🚨 必考坑点:同名但不相关的列被错误匹配!
- 经典真题:查出所有学生的名字和他们选修的课程名字。
- 错解:
select name, title from student natural join takes natural join course; - 解析为什么错:
student表里有dept_name(学生所在的系),course表里也有dept_name(开这门课的系)。如果你用连续的natural join,系统会强制要求student.dept_name = course.dept_name。结果就是:只输出学生选了自己本系的课! 那些跨系选修的课全被过滤掉了! - 正解:使用
join ... using或者把后面的自然连接改成join ... on。
- 错解:
② 外连接 (Outer Join) —— “一个都不能少”
外连接为了防止数据丢失,会把没有匹配上的行也硬拉进来,空位填 NULL。
- Left outer join (左外连接):保留左表的所有行。右表没匹配上的,填 NULL。
- 例子:查出所有学生的选课情况(包括一门课都没选的乖宝宝)。
student left outer join takes on student.ID = takes.ID。没选课的学生,课号位置全是 NULL。
- 例子:查出所有学生的选课情况(包括一门课都没选的乖宝宝)。
- Right outer join (右外连接):保留右表的所有行。
- Full outer join (全外连接):左右表的所有行全保留,互相没匹配上的全填 NULL。
2. 视图 (Views) —— 数据库里的“海市蜃楼”
考点:视图的作用,以及判断一个视图能不能被 INSERT / UPDATE。
- 概念:视图是一张虚拟表。它本身不存数据,只存一个 SQL 查询逻辑。每次你查视图,系统就临时跑一遍那个底层的 SQL。
- 作用:
- 简化复杂查询:把一长串恶心的多表 JOIN 包装成一个视图,以后直接
select * from 视图名即可。 - 安全性:建一个“员工视图”,里面把“工资”列去掉,然后把这个视图开放给普通员工看。
- 简化复杂查询:把一长串恶心的多表 JOIN 包装成一个视图,以后直接
- 物化视图 (Materialized Views):
- 和普通视图不同,它是真实占用硬盘空间把结果存下来的!适用于那些查询极慢、但又不经常更新的报表数据。底表更新时,物化视图也需要同步更新(视图维护)。
- 🚨 视图更新的硬性限制(必考选择题):
- 如果用户对视图执行
INSERT,数据库必须能精准推导出底层原表该怎么INSERT。所以,只有极其简单的视图才能更新! - 不能更新的死穴:
FROM后面有多张表(连表视图)。- 有聚集函数(如
SUM,AVG)。你想啊,你把视图里的“平均工资”改成 5000,数据库怎么知道该把底层每个人的工资改成多少? - 有
GROUP BY或HAVING。 - 有
DISTINCT(去重)。
- 如果用户对视图执行
3. 事务 (Transactions) —— 同生共死的兄弟
考点:选择/填空考原子性,以及 commit 和 rollback 的作用。
- 概念:事务是由一系列 SQL 语句组成的逻辑工作单元。
- 原子性 (Atomicity):要么全做完,要么全不做。
- 指令:
commit(提交):盖章确认!一旦 commit,数据修改永久生效,就算下一秒停电也不怕。rollback(回滚):发现不对劲(比如余额不足了),赶紧撤销!数据库会恢复到事务开始前的状态,仿佛一切都没发生过。
4. 完整性约束 (Integrity Constraints) —— 数据库的门神
考点:外键的级联操作(Cascade),非常喜欢出逻辑推演题。
除了建表时的 PRIMARY KEY,还有这些门神:
not null:不准为空。unique:唯一约束。注意,unique列允许存在多个 NULL 值(因为 NULL 和 NULL 比较结果是 unknown,不算重复)。check(谓词):比如check (semester in ('Fall', 'Winter', 'Spring', 'Summer')),或者check (budget > 0)。- 🚨 外键的级联操作 (Cascading Actions):
- 场景:物理系 (Physics) 在
department表里被删除了,但instructor表里还有一堆老师属于物理系。怎么办? - 默认行为:报错!阻止你删除物理系(保护引用完整性)。
on delete cascade(级联删除):太残暴了!只要物理系被删,自动把属于物理系的老师全删掉。on delete set null:仁慈一点。物理系被删后,把属于物理系的老师的dept_name改成 NULL(变成“待定系”老师)。
- 场景:物理系 (Physics) 在
5. 授权 (Authorization) —— 谁动了我的奶酪
考点:GRANT 和 REVOKE 语法,以及“角色(Role)”的概念。
- 授权 (
GRANT):grant select, update (budget) on department to Amit;(赋予 Amit 对系表的所有行的查询权,以及修改预算列的修改权)。 - 收回 (
REVOKE):revoke select on department from Amit;注意:如果是级联收回,Amit 如果把权限转授给了 Bob,收回 Amit 的同时也会把 Bob 的收回。 - 角色 (
Role):- 痛点:学校有几千个老师,总不能一个个去写
grant吧? - 解决:创建一个“模板”(角色)。
create role instructor;(建角色)grant select on takes to instructor;(把看成绩的权限给这个角色)grant instructor to Alice;(Alice 成为老师,瞬间拥有所有权限)。
- 痛点:学校有几千个老师,总不能一个个去写
考前小测(检验一下):
- 我想查所有课程的选课情况,要求没人选的冷门课程也要显示出来(选课人数/信息为空),应该用哪种连接?(答:
course left outer join takes) - 包含
GROUP BY的视图可以执行INSERT操作吗?(答:绝对不可以,视图无法将这一行插入映射到底层表) - 设置了外键约束且带
on delete cascade,当我删除了一个部门,会发生什么?(答:不仅部门没了,该部门下的所有老师、课程等引用了该部门的子表数据,都会被数据库默默地连环删除!) - 把
SELECT权限给一个用户,但他不能把这个权限再传给别人,GRANT语句末尾应该不写什么?(答:不写with grant option)
第四章是 SQL 走向“严谨”的必经之路。掌握了它,你的数据库不仅能跑,而且防雷、防黑客、防崩溃。
最后剩下的就是第五章(JDBC/触发器)了,因为你们老师说从 5.4 往后不考,那第五章的任务量就很轻了!准备好迎接最后的收尾了吗?
太棒了!我们终于来到了最后一部分:第五章(5.1 - 5.3)。
如果说前四章教你的是“如何在数据库客户端(如 Navicat, DataGrip)里敲代码”,那么第五章教你的就是“如何让数据库和真正的软件系统(如 Java/Python写的App、网站)结合起来”。
这一部分在随堂测验中,最爱考概念题(简答/选择),尤其是 “SQL注入” 和 “触发器的使用场景”。我们来把这最后三块拼图补齐:
1. 编程语言访问 (JDBC/ODBC) —— 跨界联名
考点:为什么需要它?SQL注入的原理是什么?
① 为什么需要宿主语言(Java/C++等)?
- 因为 SQL 是“偏科”的:SQL 是声明式语言,它是为了查数据而生的,但它不是图灵完备的。它不能写图形界面 (UI),不能接收用户的键盘输入,不能发网络请求。
- 解决方案:用 Java/C++ 作为“宿主语言”写软件逻辑,通过 JDBC (Java Database Connectivity) 或 ODBC 接口,把 SQL 语句打包发送给数据库,数据库查完后再把结果(如 ResultSet)传回给 Java。
② 预备语句 (PreparedStatement) 与 SQL 注入(⭐⭐⭐ 必考必考必考!)
这是本章最重要的概念,极有可能出简答题!
- 什么是 SQL 注入 (SQL Injection)?
- 黑客原理:如果程序员用字符串拼接的方式生成 SQL,黑客可以通过输入特殊字符(如单引号
')来篡改原本的 SQL 逻辑。 - 经典例子:程序原本的代码是
SELECT * FROM user WHERE name = '+ 用户输入 +'。 - 黑客在输入框里输入:
a' OR '1'='1。 - 拼接后的 SQL 变成了:
SELECT * FROM user WHERE name = 'a' OR '1'='1'。因为1=1永远为真,这个查询会把数据库里所有用户的密码全泄露出来!
- 黑客原理:如果程序员用字符串拼接的方式生成 SQL,黑客可以通过输入特殊字符(如单引号
- 怎么防?用预备语句 (PreparedStatement)!
- 原理:它使用占位符
?(如:SELECT * FROM user WHERE name = ?)。数据库会先编译这句带?的骨架,然后再把用户的输入纯粹当成“数据值”填进去。 - 这样一来,黑客输入的
' OR '1'='1只会被当成一个奇怪的名字字符串,而不会被当成可执行的 SQL 代码。 - 附带好处(提高效率):预备语句在数据库里只编译一次,如果后续只是参数
?改变,可以直接复用执行计划,速度更快。
- 原理:它使用占位符
③ 元数据 (Metadata) 的作用
- 概念:“关于数据的数据”。比如,你查询返回了一张表,这张表有几列?每一列叫什么名字?数据类型是 varchar 还是 int?
- 作用:让 Java 程序在运行的时候,能够动态地认识并处理未知的数据表。
2. 函数与过程 (Functions and Procedures) —— 数据库里的微服务
考点:知道它们的作用和参数类型的区别。
- 核心思想:把业务逻辑(比如“判断一个学生是否满足毕业条件”)直接写在数据库里,而不是写在 Java 代码里。
- 优势:多个应用端(Web端、手机端)可以直接调用,不需要各自写一遍逻辑;减少了网络传输的数据量。
- 区别:
- 函数 (
Function):必须返回一个值(或者返回一张表)。可以直接嵌在 SQL 语句里使用,比如SELECT dept_count('Physics');。 - 过程 (
Procedure):不直接返回值,而是用来执行一段动作。通过CALL procedure_name()来调用。
- 函数 (
- 过程的参数类型:
IN:传进去的参数。OUT:用来把结果传出来的参数(就像C语言里的指针参数)。
3. 触发器 (Triggers) —— 数据库里的自动机器人
考点:ECA规则,old row 和 new row 的适用场景,以及触发器的缺点。
① 触发器的三大件(ECA 规则)
- E (Event 事件):什么动作激活了机器人?(
INSERT,UPDATE,DELETE,可以是BEFORE或AFTER)。 - C (Condition 条件):被激活后,要不要做事?(
WHEN子句,满足条件才执行)。 - A (Action 动作):具体做什么事?(
BEGIN ATOMIC ... END里的 SQL 语句)。
② old row 与 new row(逻辑推理常考)
当数据发生变化时,触发器可以捕捉到变化“前”和变化“后”的数据。
referencing old row as:指代被修改/删除之前的那行老数据。referencing new row as:指代被插入/修改之后的那行新数据。- 🚨 逻辑考点:
- 如果是
INSERT操作,没有old row(无中生有)。 - 如果是
DELETE操作,没有new row(灰飞烟灭)。 - 如果是
UPDATE操作,既有old row,也有new row。
- 如果是
③ 何时不该用触发器?(拔高理解题)
以前人们喜欢用触发器来做“自动算总分”、“自动备份表”。现在为什么不推荐了?
- 级联副作用(幽灵BUG):A触发器更新了表B,表B的更新又触发了C触发器… 出了BUG程序员根本找不到源头,系统极易崩溃。
- 性能极差:大批量导入数据时,每一行都触发一次动作,数据库会卡死。
- 有更好的替代方案:
- 想要自动算总计数据?用 物化视图 (Materialized Views)。
- 想要自动备份/同步数据?用数据库自带的 复制机制 (Replication)。
最后一测(通关检验):
- 防止 SQL 注入最标准、最有效的方法是什么?(答:使用预备语句 PreparedStatement)
- 触发器在处理
INSERT语句时,能不能引用old row?(答:不能,插入操作只有新数据,没有老数据) - 把复杂的计算逻辑写成数据库的“函数 (Function)”,相比写在 Java 里有什么好处?(答:统一业务逻辑,减少网络传输开销,能直接嵌在SQL查询中使用)
🎉 复习全景总结 & 考场策略
至此,你的1-5章知识大纲已经全部串联完毕!
考场上怎么拿高分?
- 先扫一眼大题,把关系代数和SQL的题干读一遍。 如果是长句子,用笔在试卷上圈出涉及了哪几张表。
- 写SQL不要慌,按照
FROM -> WHERE -> GROUP BY -> HAVING -> SELECT的脑回路一步步往下写。 记得检查GROUP BY的“连坐规则”。 - 遇到概念题拿不准(比如第一章和第五章的简答),往“提高效率”、“保证数据一致性与安全”这两个大方向靠拢,通常都能蹭到分数。
- 遇到
JOIN:如果不确定列名是否完全一致且安全,宁可写A JOIN B ON A.id = B.id,也绝对不要手贱去写A NATURAL JOIN B,很多老师专扣这个分!
你的思路现在非常清晰,大框架已经全在脑子里了。今晚好好睡一觉,明天考场上见题拆题,一定没问题的!祝你考试顺利,一举拿下!💪