21050 字
105 分钟
数据管理基础
2026-03-04

成绩组成 4:6

C1 绪论#

数据库的基本概念#

  1. ⭐数据库、DBMS、数据库系统

    概念含义
    数据库 DB长期存储、有组织、可共享的大量数据的集合
    数据库管理系统 DBMS管理数据库的软件,位于应用程序和数据库之间(如 MySQL、Oracle、SQLSever)
    **数据库系统 DBS **数据库、DBMS、应用程序、数据库管理员、硬件等构成的整体
    数据库应用系统面向具体业务开发的应用程序及其数据库环境 = 数据库 + DBMS + 应用程序 + 数据库管理员 +硬件环境
  2. ⭐文件系统 vs 数据库

    对比角度文件方式数据库方式
    分散/统一数据分散在不同文件数据统一组织和管理
    共享共享困难支持多用户共享
    冗余冗余较多可以控制冗余
    耦合/独立程序与数据耦合较强具有数据独立性
    性质一致性、安全性难保证DBMS 统一保证完整性、安全和并发
    适用场景适合简单、独立的小规模数据适合长期、共享、结构化业务数据
  3. 数据管理技术的产生和发展:人工管理阶段 → 文件系统阶段 → 数据库系统阶段

  4. 数据库系统的特点

    1. 数据结构化
    2. 数据共享性高,冗余度低、易扩充
    3. 数据独立性高
    4. 数据由数据库管理系统 统一管理和控制

数据模型的组成要素 & 常用数据模型#

  1. ⭐数据模型#

    • 两大类、共三种数据模型:概念数据模型、 逻辑数据模型、物理数据模型

    • 数据模型的组成要素:数据结构、数据操作、数据约束 (二维关系表、原则/插入等、实体完整性)

    • ⭐关系模型基本概念#

      象集1
      象集2

      alt text —>


数据库的三级模式#

  1. 从数据库应用开发人员角度看,数据库通常采用 三级模式结构
    层次描述内容
    外模式某一类用户看到的局部数据,也叫用户视图
    模式/概念模式整个数据库的全局逻辑结构
    内模式数据的物理存储结构、文件组织和存取路径
    图片描述

两种数据独立性#

  1. 逻辑数据独立性:概念模式改变时,外模式和应用程序尽量不用改变。
    例如增加一个属性,只需调整外模式与概念模式之间的映像,原有应用仍可使用原来的视图。
  2. 物理数据独立性:内模式改变时,概念模式和应用程序不用改变。
    例如把顺序文件改成 B+ 树索引,应用程序仍然执行相同的 SQL。

C2 关系数据库#

关系数据结构#

  1. 关系
    1. 关系模型只有单一的数据结构:关系;
      关系模型的逻辑结构:二维表
    2. 关系:在域 D1,D2,…,DnD_1, D_2, \dots, D_n 上的关系 RR 也是一个 nn 元有序组的集合, 并且是其笛卡尔积的一个 子集:R⊆D1×D2×⋯×DnR \subseteq D_1 \times D_2 \times \dots \times D_n
      • 属性:二维表中的 每一列,被称为是该关系中的一个‘属性’
      • 元组 tuple:二维表中的 每一行,(d1,d2,…,dn)(d_1,d_2,…,d_n),t[Ai]t[A_i]表示元组t在属性 AiA_i上的取值;t[i]t[i] 表示元组t在第i列上的取值。如:(李敏君,软件工程专业,19)
      • 分量:元组中的每一个值did_i叫做一个分量.如:李敏君、软件工程专业、19
        元组连接:trtst_r t_s上弧线,表示把两个表连接起来。
      • 基数:一个域允许的不同取值个数
      • 关系的表示:在域 D1,D2,…,DnD_1,D_2,…,D_n 上的关系R可以被表示为 R(A1,A2,…,An)R(A_1,A_2,…,A_n)
        其中 AiA_i 是属性名 eg:“专业”
    3. 域
      相同数据类型的值的集合,域内元素互不相同。如:整数集合、{男,女}、char (25) 字符串集合
    4. (候选)码 Key
      若关系中的某一 属性组 的值能唯一地标识一个元组,而其所有的真子集都不能,则称该 属性组 为关系的 ‘候选码’ ,简称 ‘码’
    5. 主码:
    6. 全码 All-key:关系中的所有属性构成的属性组是这个关系的候选码,称为 ‘全码’(All-key)
    7. 主属性 与 非主属性/非码属性
      • 候选码中的诸属性称为该关系的 ‘主属性’(Prime attribute)
      • 不包含在任何侯选码中的属性称为该关系的 ‘非主属性’/‘非码属性’

⭐关系的完整性约束#

  1. 实体完整性
    主码属性不能为空 NULL
  2. 参照完整性
    1. 外码值要么为空,要么等于被参照关系的主码值
    2. 外码:
      参照关系:R(拿着外码的表,比如学生表)
      被参照关系:S(被引用主键的表,比如专业表)
      外码1
      外码2
      外码2
  3. 用户定义的完整性

⭐关系代数#

  • 关系运算 img_7.png 选择:σSdept=′IS′(Student)\sigma_{Sdept='IS'}(Student)、投影:πSdept(Student)\pi_{Sdept}(Student)

  • 例

    • 所有:除运算÷;只: alt text alt text
  • 最大/最高 在当前的所有顾客中, 查询折扣(discnt)最高的顾客的编号?
    令 S:=CS := C, “折扣不是最高的顾客的id”
    R2:=πC.cid(σC.discnt<S.discnt(C×S))R_2 := \pi_{C.cid}(\sigma_{C.discnt < S.discnt}(C \times S))
    答案是 πcid(C)−πC.cid(σC.discnt<S.discnt(C×S))\pi_{cid}(C) - \pi_{C.cid}(\sigma_{C.discnt < S.discnt}(C \times S))

    象集1
    象集1
    象集1
    象集1
  • 象集
    该属性值对应的其他属性值集合,相当于除法

    象集1
    象集2
  1. 除运算 R ÷ S
    找出R、S中相同的属性列(B、C),R 剩下的属性列(A) 作为结果。
    aia_i的所有(bjb_j,cjc_j),aia_i包含S中的全部b、c。

    外连接
    左右外连接
    • 例
    象集1
    象集1

C3 SQL#

  • SQL基本执行结构
    SELECT ...
    FROM ...
    WHERE ...
    GROUP BY ...
    HAVING ...
    ORDER BY ...;
    逻辑顺序:FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY

基本表 TABLE#

  1. 定义基本表
    PRIMARY KEY 主键,唯一标识一行数据,不能重复、不能为空
    UNIQUE 唯一,不能重复,但能为空
    外键 FOREIGN KEY (cno) PREFERENCE course(cno) ON UPDATE/DELETE 规约条件

    CREATE TABLE Student
    (Sno CHAR(9) PRIMARY KEY, /* 列级完整性约束条件, Sno是**主码**/
    Sname CHAR(20) UNIQUE, /* **约束**,Sname的取值具有唯一性*/
    Ssex CHAR(2) NOT NULL CHECK (Ssex IN ('男', '女')),/* 非空且只能是男/女 */
    Sage SMALLINT,
    Sdept CHAR(20)
    );
    CREATE TABLE enrollment(
    sno char(9) NOT NULL,
    clsno char(8) NOT NULL,
    grade INT CHECK (grade BETWEEN 0 AND 100),
    PRIMARY KEY(sno,clsno), -- 课程班代码和学号联合构成PRIMARY KEY
    );
    CREATE TABLE courseclass(
    clsno char(8) PRIMARY KEY,
    cno char(8) NOT NULL,
    tno char(9) ,
    -- 先定义再外键 + 违约规则
    FOREIGN KEY (cno) REFERENCES coures(cno) ON UPDATE CASCADE ON DELETE RESTRICT,
    FOREIGN KEY (tno) REFERENCES teachers(tno) ON UPDATE CASCADE ON DELETE SET NULL
    -- 父表更新cno,子表cno自动同步更新;父表删除cno,子表还有该课程就禁止删除
    -- 父表更新tno,子表tno自动同步更新;父表删除tno,子表对应的tno自动设为NULL
    );
    • 违约规则
      什么是违约? 父表更新主键/删除父表记录会破坏参照关系,触发违约
      关键字中文含义
      CASCADE级联父表改 / 删 → 子表自动跟着改 / 删
      SET NULL置空父表删 → 子表外键自动设为 NULL
      RESTRICT限制 / 拒绝数据库直接禁止父表的改/删操作
  2. 修改基本表(ALTER TABLE)

    • ADD新增列/完整性约束
      ALTER TABLE Student
      ADD COLUMN S_email VARCHAR(50) NOT NULL UNIQUE; -- 增加邮箱列,要求非空且唯一
      ADD CONSTRAINT chk_sex CHECK (Ssex IN ('男', '女')); -- 为 Ssex 增加 CHECK 约束(性别只能是男 / 女)
    • DROP 删除列
      ALTER TABLE Student
      DROP COLUMN S_email CASCADE; --删除“邮箱”列,默认RESTRICT
      DROP CONSTRAINT chk_sex; -- 删除性别CHECK约束
    • 修改列的定义
      ALTER TABLE Student
      ALTER COLUMN Sage INT; -- 修改数据类型:年龄从SMALLINT改为INT
      ALTER COLUMN Sname CHAR(30); -- 修改列长度(姓名从 CHAR (20) 改为 CHAR (30))
      ALTER TABLE Course ADD UNIQUE(Cname); -- 增加课程名称必须取唯一值的约束条件
  3. 删除基本表

    DROP TABLE <表名>[RESTRICT| CASCADE];
    • RESTRICT:只有在该表没有被其他数据库对象依赖时,才能删除。
    • CASCADE:删除该表的同时,还会删除依赖于该表的相关对象或依赖关系

视图 VIEW#

  1. 视图的作用?
    简化复杂查询;
    为不同用户提供不同数据视图;
    隐藏敏感属性,提高安全性;
    阻止不符合条件的数据加入/修改成不符合条件的数据。
  2. 定义视图 AS
    CREATE VIEW S_G(Sno,Gavg) -- 可选:列名
    AS
    SELECT Sno,AVG(Grade)
    FROM SC
    GROUP BY Sno;
  3. 查询视图
  4. 更新视图
  5. 删除视图
    DROP VIEW S_G [RESTRICT | CASCADE]

  1. 字符串匹配
    • ⭐字符匹配 LIKE/=
    SELECT* FROM Student WHERE Sno LIKE '24%' -- 通配符,查询学号以24开头的学生的详细信息
    SELECT* FROM Student WHERE Sno = '24%' -- 查询学号就是'24%'学生的详细信息
    • ⭐字符串中的通配符
    SELECT Sname, Sno, Ssex
    FROM Student
    WHERE Sname LIKE '刘%'; -- 查询所有姓刘学生的姓名、学号和性别
    SELECT Sname
    FROM Student
    WHERE Sname LIKE '欧阳_'; -- 查询姓"欧阳"且全名为三个汉字的学生的姓名
    SELECT Sname, Sno
    FROM Student
    WHERE Sname LIKE '_阳%'; -- 查询名字中第2个字为"阳"字的学生的姓名和学号
    SELECT Sname, Sno, Ssex
    FROM Student
    WHERE Sname NOT LIKE '刘%'; -- 查询所有不姓刘的学生姓名、学号和性别
  2. 多表连接 JOIN
    SELECT DISTINCT s.sid, s.sname
    FROM Student s
    JOIN Enroll e ON s.sid = e.sid
    JOIN Course c ON e.cid = c.cid
    WHERE c.cname = '数据管理基础'
    AND c.dept = '智软学院';
    使用 DISTINCT 是为了消除同一学生由于多条匹配记录产生的重复
    • DISTINCT 的位置:SELECT 子句;聚集函数内部。
      SELECT DISTINCT dept
      FROM Student;
      COUNT(DISTINCT sid)
      AVG(DISTINCT score)
      SUM(DISTINCT amount)
  3. 分组与 HAVING先Group 分组后 HAVING
    分组
  4. EXISTS 子查询有结果,返回TRUE;子查询无结果,返回FALSE
    SELECT Sname
    FROM Student S
    WHERE EXISTS (
    SELECT *
    FROM SC
    WHERE SC.Sno = S.Sno
    AND Cno = '1' -- 从 Student 表里,找出那些‘存在’选修 1 号课程记录的学生
    ); -- 查询选修了 1 号课程的学生
    SELECT Sname
    FROM Student S
    WHERE NOT EXISTS (
    SELECT *
    FROM SC
    WHERE SC.Sno = S.Sno
    AND Cno = '1'
    ); -- 查询没选1号课程的学生
    • 查询选修全部课程的学生
      SELECT Sname
      FROM Student
      WHERE NOT EXISTS ( -- ③ 除去没有选择课程的学生
      SELECT *
      FROM Course -- ② 有NOT EXISTS学生选择的课程中的:学生没有选择的课程
      WHERE NOT EXISTS (
      SELECT *
      FROM SC
      WHERE SC.Sno = Student.Sno
      AND SC.Cno = Course.Cno -- ① 对SC中的每门课程,去Student、Course中寻找有无记录
      ) -- 学生选择的课程
      );
      ✅ 理解:不存在一门课是这个学生没选的
    • 例
    exists
    exists
    exists
    exists

⭐例题#

  1. 所有课程都及格:HAVING MIN(grade)>=60

    分组
  2. 修完本院所有必修课

    分组
  3. 每组最大值

    分组
  4. 只讲授本院课程

  5. SQL(Structured Query Language)结构化查询语言,是关系数据库的标准语言

  6. SQL与关系数据库的三级模式alt text

  7. 核心功能:

  • 数据定义:CREATE,DROP,ALTER - 数据查询:SELECT - 数据操作:INSERT,UPDATE,DELETE - 数据控制:GRANT,REVOKE

⭐数据库安全性#

  1. 授权:授予GRANT 与 回收REVOKE
    • 授予 GRANT
      GRANT SELECT,INSERT
      ON Student
      TO U1 -- 把对Student的查询、插入权限授予用户U1
      GRANT ALL PRIVILIGES
      ON TABLE Student,Course
      TO U2,U3 -- 把对Student表和Course表的全部权限授予用户U2和U3
      转授 WITH GRANT OPTION
      GRANT SELECT
      ON Student
      TO user2
      WITH GRANT OPTION;
    • 回收 REVOKE
      REVOKE UPDATE(Sno) ON STUDENT FROM U4 -- 把用户U4修改学生学号的权限收回
      REVOKE SELECT ON SC FROM PUBLIC -- 收回所有用户对表SC的查询权限

SQL数据定义#

操作对象创建删除修改
模式 SCHEMACREATE SCHEMADROP SCHEMA-
表 TABLECREATE TABLEDROP TABLEALTER TABLE
视图 VIEWCREATE VIEWDROP VIEW-
索引 INDEXCREATE INDEXDROP INDEXALTER INDEX

定义/删除模式(CREATE/DROP SCHEMA)#

  1. 例:为用户WANG 定义一个学生-课程模式S-T

    CREATE SCHEMA “S_T” AUTHORIZATION WANG;
    CREATE SCHEMA AUTHORIZATION WANG; -- 该语句没有指定<模式名>,<模式名>隐含为<用户名> WANG
  2. 模式中定义其他
    为用户ZHANG创建了一个模式TEST,并且在其中定义一个表TAB1

CREATE SCHEMA TEST AUTHORIZATION ZHANG
CREATE TABLE TAB1 (
COL1 SMALLINT,
COL2 INT,
COL3 CHAR(20),
COL4 NUMERIC(10,3),
COL5 DECIMAL(5,2) );
  1. 删除模式
    DROP SCHEMA <模式名> <CASCADE|RESTRICT>
    • CASCADE(级联):删除模式的同时,把里面所有表/数据/对象全部删除;
    • RESTRICT(限制):模式里有任何东西(表/视图/数据),就禁止删除
      eg SCHEMA ZHANG CASCADE; 删除模式ZHANG,同时该模式中定义的表TAB1也被删除

索引 INDEX#

  1. 建立索引 CREATE INDEX
CREATE UNIQUE INDEX Coucno ON Course(Cno); -- Course表按课程号
CREATE UNIQUE INDEX SCno ON SC(Sno ASC,Cno DESC); -- 升序建唯一索引,SC表按学号升序和课程号降序建唯一索引
  1. 修改索引 ALTER INDEX
ALTER INDEX SCno RENAME TO SCSno; -- 将SC表的SCno索引名改为SCSno
  1. 删除索引 DROP INDEX
DROP INDEX Stusname; -- 删除Student表的Stusname索引

关系代数 vs SQL语言#

  1. πA1,A2,...,Am(σF(R))\pi_{A_1, A_2, ..., A_m} \left( \sigma_F ( R ) \right)其中 Ai∈head(R)A_i \in head(R) for i=1,2,…,mi = 1, 2, \dots, m
    SQL表示
    SELECT A_1, A_2, ..., A_m
    FROM R
    WHERE F
  2. 笛卡尔积 R×SR\times S
    SQL表示
    SELECT R.A_1,...,R.A_n,s.b_1,...,s.b_m
    FROM R,S
  3. θ−\theta-连接 R⋈FSR\underset{F}\bowtie S
    SQL表示
    SELECT R.A_1,...,R.A_n,s.b_1,...,s.b_m
    FROM R,S
    WHERE F
  4. 自然连接 R⋈SR\bowtie S
    SQL表示
    SELECT R.A_1,...,R.A_n,s.b_1,...,s.b_m
    FROM R,S
    WHERE R.B_1 = S.B_1 and R.B_2 = S.B_2 and ... and R.B_k = S.B_k
  5. πattr_1,attr_2,...,attr_x(σF(R×S))\pi_{attr\_1, attr\_2, ..., attr\_x} (\sigma_F (R \times S))
    SQL表示
    SELECT attr_1, attr_2, ..., attr_x
    FROM R,S
    WHERE F

SQL数据查询#

单表查询#

  1. 基本格式:SELECT SNO FROM Student WHERE Sage<18
  2. SELECT 目标子句
    • 查所有列:SELECT * FROM Student
    • 查指定列:SELECT Sno, Sname FROM Student; 查询全体学生的学号与姓名
    • 起别名:SELECT Sname,2026-Sage AS 计算(2026-Sage)结果出生年份起名为AS
    • 列去重:SELECT DISTINCT Sno FROM SC; 查询学号 alt text
    • 计算
      SELECT ordno, year(orddate), month(orddate), day(orddate)
      FROM orders; -- 查询每一份订单的编号、订购的年、月、日;
      SELECT ordno, orddate, datediff(curdate(), orddate)
      FROM orders ; -- 查询每一份订单的编号、订购日期、距离至今相隔的天数;
    • 例:查询全体学生的姓名、出生年份和所在的院系,要求用小写字母表示系名。
      SELECT Sname,'Year of Birth: ', 2014 - Sage, LOWER(Sdept)
      FROM Student;

  1. FROM 范围子句
    SELECT S.Sno, S.Sname
    FROM Student S; //S是Student的别名

  1. WHERE 条件子句
    • 比较
    SELECT Sname
    FROM Student
    WHERE Sdept = ‘CS’ ;
    WHERE Sdept <> ‘CS’;//过滤条件,相当于!=不等于
    • 确定范围
    SELECT Sname, Sdept, Sage
    FROM Student
    WHERE Sage (NOT) BETWEEN 20 AND 23; -- 查询年龄(不)在[20,23]的学生的姓名、系别和年龄
    • 确定集合
    SELECT Sname, Ssex
    FROM Student
    WHERE Sdept (NOT) IN ( 'CS','MA','IS' );-- 查询(不是)计算机科学系(CS)、数学系(MA)和信息系(IS)学生的姓名和性别。
    • ‘字符串常量’加单引号
    SELECT Sname,'Year of Birth: ', 2014 - Sage, LOWER(Sdept) FROM Student;//系名小写
    • 字符匹配 LIKE/=
    SELECT* FROM Student WHERE Sno LIKE '24%' -- 通配符,查询学号以24开头的学生的详细信息
    SELECT* FROM Student WHERE Sno = '24%' -- 查询学号就是'24%'学生的详细信息
    • 字符串中的通配符
    SELECT Sname, Sno, Ssex
    FROM Student
    WHERE Sname LIKE '刘%'; -- 查询所有姓刘学生的姓名、学号和性别
    SELECT Sname
    FROM Student
    WHERE Sname LIKE '欧阳_'; -- 查询姓"欧阳"且全名为三个汉字的学生的姓名
    SELECT Sname, Sno
    FROM Student
    WHERE Sname LIKE '_阳%'; -- 查询名字中第2个字为"阳"字的学生的姓名和学号
    SELECT Sname, Sno, Ssex
    FROM Student
    WHERE Sname NOT LIKE '刘%'; -- 查询所有不姓刘的学生姓名、学号和性别
    • 转义字符 用 ESCAPE ” 表示字符\为换码字符(转义指示符)
    查询DB_Design课程的课程号和学分。
    SELECT Cno,Ccredit
    FROM Course
    WHERE Cname LIKE 'DB\_Design' ESCAPE '\' ;
    WHERE Cname = 'DB_Design'; -- 等效
    • 涉及空值的查询
    SELECT Sno,Cno
    FROM SC
    WHERE Grade IS NOT NULL; -- 查所有有成绩的学生学号和课程号
    • 多重条件查询(AND/OR)

连接查询(多表)#

  1. 等值连接/自然连接查询=
    等值连接
  2. 自身连接 起别名 =
    查询每一门课的间接先修课(即先修课的先修课)
    SELECT FIRST.Cno, SECOND.Cpno
    FROM Course FIRST, Course SECOND -- 需要给表起别名
    WHERE FIRST.Cpno = SECOND.Cno;
    计算机网络基本概念总结
  3. 外连接
    SELECT Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade
    FROM Student LEFT OUTER JOIN SC ON (Student.Sno=SC.Sno); -- 左外连接:左边为标准,右边不存在的填NULL
    FROM Student RIGHT OUTER JOIN SC ON (Student.Sno=SC.Sno); -- 右外连接:右边为标准,右边不存在的填NULL
    FROM Student FULL OUTER JOIN SC ON S.Sno = SC.Sno; -- 全外连接,全部补NULL

嵌套查询(子查询)#

  1. IN
    计算机网络基本概念总结
    计算机网络基本概念总结
    计算机网络基本概念总结
  2. 带有比较运算符的子查询
    SELECT Sno,Sname,Sdept
    FROM Student
    WHERE Sdept = (SELECT Sdept FROM Student WHERE Sname = '刘晨');
    -- 在[例3.55]中,由于一个学生只可能在一个系学习,则可以用 = 代替IN
    SELECT Sno, Cno
    FROM SC x
    WHERE Grade >= ( SELECT AVG(Grade)
    FROM SC y
    WHERE y.Sno = x.Sno ); -- 找出每个学生超过他选修课程平均成绩的课程号。
  3. 限定比较谓词(SOME/ANY/ALL)
    -- 查询非计算机科学系中比计算机科学系任意一个学生年龄小的学生姓名和年龄
    SELECT Sname,Sage
    FROM Student
    WHERE Sage < ANY (
    SELECT Sage
    FROM Student
    WHERE Sdept = 'CS')
    AND Sdept <> 'CS' ;
    -- 聚集函数
    SELECT Sname,Sage
    FROM Student
    WHERE Sage < (
    SELECT MAX(Sage)
    FROM Student
    WHERE Sdept= 'CS ' )
    AND Sdept <> 'CS';
    < ANY → 小于最大值;
    SELECT * FROM SC
    WHERE Grade < ANY (80,90,70); -- 任意一个,小于最大值。成绩 < 90
    SELECT * FROM SC
    WHERE Grade < ALL (80,90,70); -- 所有,小于最小值。成绩 < 70
  4. EXISTS谓词 子查询有结果,返回TRUE;子查询无结果,返回FALSE
    SELECT Sname
    FROM Student S
    WHERE EXISTS (
    SELECT *
    FROM SC
    WHERE SC.Sno = S.Sno
    AND Cno = '1' -- 从 Student 表里,找出那些‘存在’选修 1 号课程记录的学生
    ); -- 查询选修了 1 号课程的学生
    SELECT Sname
    FROM Student S
    WHERE NOT EXISTS (
    SELECT *
    FROM SC
    WHERE SC.Sno = S.Sno
    AND Cno = '1'
    ); -- 查询没选1号课程的学生
    • 查询选修全部课程的学生
      SELECT Sname
      FROM Student
      WHERE NOT EXISTS ( -- ③ 除去没有选择课程的学生
      SELECT *
      FROM Course -- ② 有NOT EXISTS学生选择的课程中的:学生没有选择的课程
      WHERE NOT EXISTS (
      SELECT *
      FROM SC
      WHERE SC.Sno = Student.Sno
      AND SC.Cno = Course.Cno -- ① 对SC中的每门课程,去Student、Course中寻找有无记录
      ) -- 学生选择的课程
      );
      ✅ 理解:不存在一门课是这个学生没选的
    • 例
    exists
    exists
    exists
    exists

聚集函数/统计函数#

  1. COUNT 统计元组个数
  2. SUM 计算一列的总和/AVG 计算一列的平均值
  3. MIN 一列值中的最大值/MIN 一列值中的最小值
聚集函数1 聚集函数2

对查询结果的处理#

  1. 对查询结果排序 ORDER BY 属性名 ASC升序/DESC降序 查询选修了3号课程的学生的学号及其成绩,查询结果按分数降序排列。
    SELECT Sno, Grade
    FROM SC
    WHERE Cno= '3'
    ORDER BY Grade DESC;
  2. 对查询结果分组 GROUP BY/HAVING 求各个课程号及相应的选课人数。
    SELECT Cno,COUNT(Sno)
    FROM SC
    GROUP BY Cno; // 按照Cno为一行,相同Cno为一行
    查询选修了3门以上课程的学生学号。
    SELECT Sno
    FROM SC
    GROUP BY Sno
    HAVING COUNT(*) >3;
    • 辨析 HAVING 与 WHERE alt text
  3. 指定结果列的列标题
    SELECT Sname NAME,'Year of Birth:' BIRTH,2014-Sage BIRTHDAY,
    -- Sname一列的结果列标题为NAME,'Year of Birth:'常量列的列标题为BIRTH…
    FROM Student;
  4. 查询结果
    WHERE → GROUP → SELECT → ORDER   WHERE → GROUP → HAVING → SELECT → ORDER
    计算机网络基本概念总结
    计算机网络基本概念总结

集合操作#

  1. 并操作 UNION [ALL] alt text
  2. 交操作 INTERSECT [ALL]
  3. 差操作 EXCEPT [ALL]
    计算机网络基本概念总结
    计算机网络基本概念总结

基于派生表的查询#


数据更新#

  1. 插入#

    1. 格式
      INSERT
      INTO <表名> (属性名1,属性名2,…)
      VALUES (expr1|NULL , expr2|NULL ,…)
      alt text
    2. 插入子查询结果
      INSERT
      INTO <表名>(属性1,属性2,…)
      子查询
      alt text
  2. 修改#

    1. 格式
      UPDATE <表名>
      SET <属性1>=<expr1>,<属性2>=<expr2>
      WHERE <条件>
      alt text alt text
  3. 删除#

    1. 格式
      DELETE
      FROM <表名>
      [WHERE <条件>]
      alt text

事务#

  1. 定义 是用户定义的一个数据库操作序列,这些操作要么全做,要么全不做
  2. 例 alt text
  3. 事务的特性(ACID) 原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)
  4. 定义事务
    • 事物的启动:隐式方式(由数据库管理系统来决定,何时为何用户启动一个新的事务)
    • 事物的结束:用户调用commit或rollback命令,显式地结束当前事务;由数据库管理系统强行结束一个用户的当前正在运行中的事务
    1. 事务启动方式#

      • 数据定义命令 DDL
        只要你执行 CREATE、ALTER 等定义语句,系统自动把这一条语句当成一个独立事务。
        执行前,如果你正在做其他操作,系统会自动先提交之前的事务。
      • 将系统设为自动提交方式(打开自动提交标志)
        这是最常见的默认状态。每一条 SELECT、UPDATE 等操作,做完后系统自动帮你 COMMIT,立即生效。
      • 数据操纵命令(DML)
        如果你没有开启自动提交,当你执行 INSERT/UPDATE/DELETE 时,系统检测到你没有事务,就自动帮你开启一个新事务,等着你手动提交或回滚。
    2. 事务结束方式#

      • 事务提交:COMMIT
        事务正常结束,确认所有操作生效
      • 事务回滚:ROLLBACK
        事务异常终止,撤销所有操作。保存点 savepoint,支持部分回滚。只撤销保存点后的操作
  5. 相关的SQL语句
    • 事务结束命令 事务提交命令:COMMIT/事务放弃命令:ROLLBACK
    • 事务设置命令
      • 设置事务的自动提交命令:SET AUTOCOMMIT ON | OFF
      • 设置事务的类型:SET TRANSACTION READONLY | READWRITE
    • 在MySQL数据库中,设置事务自动提交功能的SQL命令格式是
      • SET AUTOCOMMIT = 0; /* 关闭事务自动提交功能 */
      • SET AUTOCOMMIT = 1; /* 打开事务自动提交功能 */
    • 只读/读写型事务 SET TRANSACTION READONLY | READWRITE ;
    • 事隔离级别——解决相互干扰
      1. READ UNCOMMITTED 读未提交
      2. READ COMMITTED 读已提交
      3. REPEATABLE READ 可重复读
      4. SERIALIZABLE 串行化
    • 基于封锁的并发控制(Locking)——具体执行策略
      1. 读锁(共享锁/S锁) 事务 T 持有读锁时,只允许别人读,不允许写。作用:保证大家看到的是同一时刻的数据。
      2. 写锁(排他锁/X锁) 事务 T 持有写锁时,别人既不能读,也不能写。作用:保证修改操作不被打断,原子性执行。
      3. 互斥原则 一个数据对象上,同一时刻只能有一种锁(要么一堆读锁,要么一个写锁),不能混着来。

SQL中的空值#

注意取值 alt text

视图#

  1. 格式
    CREATE VIEW <视图名> [(<列名> [,<列名>]…)]
    AS <子查询>
    [WITH CHECK OPTION];
  2. 例-行列子集视图 若一个视图是从单个基本表导出的,并且只是去掉了基本表的某些行和某些列,但保留了主码,我们称这类视图为行列子集视图。 alt text
  3. WITH CHECK OPTION alt text 阻止不符合条件的数据加入/修改成不符合条件的数据…/而基本表没有限制
  4. 建立视图 alt textalt text
  5. 删除视图 DROP VIEW <视图名> [CASCADE] alt text
  6. 查询视图
  7. 更新视图

C4 数据库的安全性#

数据安全性概述#

  1. 数据库安全性:保护数据库防止非法使用造成的数据泄露、更改或破坏,是数据库系统核心性能指标之一

  2. 数据库不安全因素 & 安全措施#

    • 非授权用户对数据库的恶意存取和破坏:用户身份鉴别、存取控制、视图
    • 数据库中重要或敏感的数据被泄露:强制存取控制、数据加密存储、加密传输
    • 安全环境的脆弱性:建立可信计算机系统
    • 故障/误操作/并发访问
  3. 安全标准#

    • 美国国防部颁布TCSEC(DoD85) → 不同国家在其基础上建立的评估准则ITSEC/CTCPEC/FC → CC (国际通用标准)
    • TCSEC/TDI安全级别划分(从低到高)/ CC评估保证级(EAL)划分
    TCSEC划分
    CC评估保证级划分
    - 中国标准:GB 17859-1999 ![alt text](image-42.png)
  4. 计算机系统的安全模型

    计算机系统的安全模型
  5. 数据库管理系统安全性控制模型 alt text 数据库安全性控制的常用方法:用户标识和鉴定、存取控制、视图、审计、数据加密

数据库安全性控制#

数据库安全性控制的常用方法:用户标识和鉴定、存取控制、视图、审计、数据加密

用户身份鉴别#

系统提供的最外层安全保护措施
用户标识 = 用户名 + 用户标识号(用户标识号在系统整个生命周期内唯一)
用户身份鉴别的方法:静态口令鉴别、动态口令鉴别、生物特征鉴别(掌纹/虹膜)、智能卡鉴别

存取控制#

  • 组成:定义用户权限,并将用户权限登记到数据字典中 + 合法权限检查(用户发出存取数据库的操作请求后,DBMS根据字典检查权限)
  • 存取控制方法:自主存取控制、强制存取控制
    alt text

自主存取控制 DAC#

  1. SQL支持:通过 GRANT语句、REVOKE语句 提供支持
  2. 核心目标:
  3. 用户权限的组成要素:数据库对象 + 操作类型 alt text
  4. 用户存取权限的方式
    (i) 客体的属主(客体的创建者)自动拥有客体上的所有存取权限
    (ii) 拥有权限的用户可以自主地将他拥有的权限传授给在数据库系统中注册的其他用户 5. 访问控制检查流程 alt text 第一步:是不是管理员?第二步:是不是客体的属主?第三步:有没有被授予对应的权限?(检查用户 S 是否被授予了“以方式A 访问 客体O”的权限)

数据库角色 ROLE#

强制存取控制 MAC#

其他安全技术#

视图机制、审计(Audit)、数据加密、其他安全性保护



C7 数据库设计#

数据库设计的基本方法#

设计方法对象目的
新奥尔良法整体的数据库设计流程方式覆盖各阶段
基于E-R模型设计概念结构设计用 E-R / EER 图把用户需求抽象成实体、属性、联系
3NF设计方法逻辑结构设计将概念模型转为关系表,并保证满足3NF
面向对象的数据库设计方法面向对象数据库把实体看作对象,属性/方法封装在对象中
统一建模语言(UML)方法概念建模/逻辑设计用类图、对象图、时序图等 UML 工具表示

数据库设计基本步骤(新奥尔良法)#

数据库的设计
工作所属阶段
收集业务需求、数据流需求分析
画 ER/EER 图概念结构设计
ER 转关系模式、规范化逻辑结构设计
设计索引、文件组织、聚簇物理结构设计
建表、装载数据、编程数据库实施

1. 需求分析#

  1. 目标:明确用户信息需求(What)与处理需求(How),为概念设计提供基础

  2. 需求分析产出结果#

    • 数据字典(学号:字符型,10位,唯一标识学生)
    • 用户需求规格说明书(学生可以选课、退课、查成绩;教师可以录入成绩)
    • 这两个结果是概念结构设计的基础输入(为下一步画 E-R 图提供依据)
  • 数据字典 DD#

    1. 定义:数据字典是对数据库中数据的描述,也叫元数据/基础数据

      • 例:具体数据:张三,20240001,数据库原理,88
        元数据:学号是 CHAR(10),姓名是 VARCHAR(20),成绩是 0~100 的整数
    2. 数据字典的内容#

      • 数据项#

        数据项是不可再分的数据单位,是数据的最小组成单位

      • 数据结构#

        数据结构:由若干数据项/数据结构组成,反映数据之间的组合关系

      • 数据流#

        数据流:数据结构在系统内部传输的路径(数据从哪里来,到哪里去)

      • 数据存储#

        数据存储:数据结构停留或保存的地方,也是数据流来源和去向之一(数据存在哪里)

      • 处理过程#

        • 处理过程:系统对数据进行加工处理的过程。处理过程的具体处理逻辑一般用判定表或判定树来描述。
        • 判定表 & 判定树#

          alt text

2. 概念结构设计#

  1. 概念结构设计:把需求抽象成概念模型

  2. 描述概念模型的工具:E-R 模型 / EER 模型

  3. 概念结构设计方法#

    自顶向下、自下向上、二者混合策略、逐步扩张(学生的核心需求和概念结构 → 再扩展教师等其他需求和概念结构) alt text


E-R模型设计原则#

i、实体 or 属性#

  1. 原则:能作为属性处理的,尽量作为属性处理,以简化 E-R 图

  2. 两条判断准则:

    • 如果某个对象本身还需要描述其他性质,应作为实体
    • 如果某个对象还要和其他实体发生联系,应作为实体
  3. 例

    数据库的设计

ii、实体 or 联系#

  1. 实体:可以独立存在的持久对象

    • 例:学生、课程、商品、顾客、订单
  2. 联系:因为某种事情发生而产生的信息,通常依赖多个实体

    • 例:学生选课、顾客购买商品、教师讲授课程
  3. 有些事件也可以被设计成实体

    • 例:订单
      • 如果只是简单零售购买行为。
        若购买动作有属性(购买时间、购买数量等),这些信息只在购买发生时才存在,不能直接放在顾客/商品上 → 属于联系属性购买[时间、数量] 顾客 —— 购买(时间,数量) —— 商品
      • 如果大量购买,订单有订单号、时间、金额、状态等属性,应把订单作为实体 顾客 —— 下达 —— 订单;订单 —— 包含 —— 订单明细

iii、二元联系 or 多元联系#

  1. 二元联系:两个实体之间的联系
    • 例: 学生 —— 选修 —— 课程
  2. 多元联系:三个或更多实体之间的联系
    • 例:供应商给某项目供应某零件
      联系上可以有属性:供应量、供应日期、价格 供应商 —— 供应 —— 项目 —— 零件

iv、属性依附于实体 or 联系#

  1. 实体属性:实体本身具有的属性

    • 例: 学生姓名 属于 学生;课程学分 属于 课程
  2. 联系属性:跟随联系存在而存在,消亡而消亡的属性

    • 例: 学生 —— 选修(成绩, 选课时间) —— 课程

E-R图集成#

  • 处理冲突:命名冲突、属性冲突、结构冲突
  • 消除冗余:冗余数据可由基本数据推出,冗余联系可由其他联系推出(适当保留提高效率)

3. 逻辑结构设计#

  • 逻辑结构设计:把 E-R 图翻译成关系表

  • 实体集 & 属性 → 表#

    1. 规则1:实体集转换为关系模式
      • E-R图中有实体:科室、医生、病人、病例
        → 科室表、医生表、病人表、病例表
      • E-R图中有实体:医生,有属性:医生号,姓名,职称
        → 医生(医生号,姓名,职称)
    2. 规则2:组合属性拆成子属性
      • 不写emp_address,而是子属性(staddress、city、state、zipcode 要么全为空,要么全不为空) alt text
    3. 规则3:多值属性拆成新表
      • 对于学号S1307,姓名王承志,选修课程(Database, Operating System, Computer Network)
      • 方法一:纵向展开;方法二:分解出去,单独成表 alt text
  • 联系转换 & 全参与/非全参与#

    • 补充:实体集与联系的全参与/非全参与 alt text
    1. 1:1联系转换

      • 1:1 联系可以单独建表,也可以合并到任意一端(要考虑是否全参与)

      • 规则

        参与情况建表方式例子
        两边非全参与(0..1/0..1)联系单独建表电单车—电池
        一边全参与(1..1),一边非全参与(0..1)依赖存在方+依赖的主码人—驾驶证
        两边全参与(1..1/1..1)联系和实体合并成一个表学生—校园卡
      • 例:非全参与、非全参与(分开单独建表)

        数据库的设计
      • 例:全参与、非全参与(依赖存在的全参与端驾驶证要加上依赖存在的人的主码)

        数据库的设计
      • 例:全参与、全参与(合并)

        数据库的设计
    2. 1联系转换

      • 1 联系通常把 1 端的主码加入到 n 端作为外码
      • 多端全参与:多方加上外码 alt text
      • 多端非全参与:3张表 alt text
    3. m联系转换

    • 建3张表
    • 例:病人去医生那就诊(一个医生有多个病人,一个病人也有多个医生)
    病人(病人号,姓名)
    医生(医生号,姓名)
    就诊(病人号,医生号,就诊时间,就诊记录)
    1. 多元联系转换

      • 实体建表之外,多元联系也建一个表
      • 例:供应商向项目供应零件(E-R图中E-R 图:供应商 —— 供应 —— 项目 —— 零件)
        某供应商给某项目供应某零件,供应量是多少。
      供应商(供应商号, 供应商名)
      项目(项目号, 项目名)
      零件(零件号, 零件名)
      供应(供应商号, 项目号, 零件号, 供应量)
    2. 单个实体集内部的联系转换

      • 例:职工之间存在领导关系
        这里“领导职工号”也是职工号,表示该职工的上级(1:1)
      职工(职工号, 姓名, 领导职工号)
      • 如果是 m 的内部关系,需要新建关系
      职工(职工号, 姓名)
      合作(职工号1, 职工号2, 项目名)
      • 例:一个职工可以管理多个下级职工、一个职工只能有一个上级职工 alt text
    3. ISA联系转换(父子类)

      • 方法一:建3个表(不相交 + 部分特化)
        建学生(),教师(),职工(),硕导(),博导() alt text
      • 方法二:只建2个子表(不相交 + 完全特化II)
      • 方法三:建1个表
  • 具有相同码的关系模式合并

    1. 如果两个关系模式具有相同主码,且语义上属于同一对象,可以考虑合并
    2. 例:
    学生基本信息(学号, 姓名, 性别)
    学生学籍信息(学号, 专业, 入学年份)

    可以合并为:学生(学号, 姓名, 性别, 专业, 入学年份)

数据模型优化#

  1. 数据模型优化通常用规范化理论作指导
  2. 目标:
    • 减少数据冗余(拆成多个表)
    • 避免更新异常
    • 避免插入异常
    • 避免删除异常
    • 提高数据一致性
  3. 分解方法:水平分解(分行:分成23级学生、24级学生)、垂直分解(分列:分成学生基本信息+联系方式)
  4. 设计用户子模式(视图)
    • 视图作用:
      简化用户操作;
      满足不同用户需求;
      隐藏敏感数据,保证安全性;
      封装复杂查询。

物理结构设计#

  1. 物理结构设计:为逻辑数据结构选择最适合应用环境的物理结构
  2. 常见的存取方法
    方法适合场景
    B+ 树索引范围查询/连接/排序/最值
    Hash 索引等值查询/连接
    聚簇存取经常按某属性集中访问的数据

数据库实施#


⭐C8 数据库编程#

SQL语言的三种使用方式:交互式SQL(可独立运行)、嵌入式SQL(主语言+ESQL)、过程化SQL

嵌入式SQL#

  1. 嵌入式SQL是将SQL语句嵌入程序设计语言中,被嵌入的程序设计语言称为 (宿)主语言。如Java、C++
  2. 格式#

    前缀 EXEC SQL  后缀 ;   into获取结果元组值   前缀 : 来区分主变量

    EXEC SQL select Sno, Sname, Sage
    into :hsno, :hsname, :hsage -- 输出主变量(由SQL语句对其赋值/设置状态信息,返回给应用程序)
    from Student
    where Sno = :givensno ; -- 输入主变量(由应用程序对其赋值,在SQL语句引用)
    -- 根据程序传入的学号,从 Student 表查询单个学生的学号、姓名、年龄,并把结果存入主变量
  3. SQL通信区(SQLCA)#

    SQL语句执行后,数据库系统需要反馈给应用程序的信息:描述系统当前工作状态、描述运行环境
    这些信息将送到并保存在SQL通信区中、应用程序从SQL通信区中获取这些状态信息。

    • 定义SQLCA
      用 EXEC SQL INCLUDE SQLCA 定义
    • 使用SQLCA
      SQLCA中有一个用于存放每次执行SQL语句后返回当前SQL语句执行状态的代码变量SQLCODE;
      每执行完一条SQL语句之后都测试:执行成功返回SUCCESS(0),否则表示出错或异常。 SQLCODE的值,以了解该SQL语句执行情况并做相应处理。
  4. 主变量#

    嵌入式SQL语句中可以使用的主语言程序变量

    • 指示变量
      是一个整型变量,是一种特殊的主变量,用来“指示”相关主变量的值是否为 空值
      指示变量的用途:指示输入主变量是否为空值;检测输出变量是否为空值,值是否被截断

      指示变量取值含义
      0主变量正常接收到了非空的数据库值
      > 0数据库字符串被截断,只存了部分到主变量
      -1数据库值是NULL,主变量里的值无意义
    • 例:查询返回的Grade属性值是否为NULL/根据课程号把该课程的成绩都置为空。

      EXEC SQL SELECT Sno, Cno, Grade
      INTO :Hsno, :Hcno, :Hgrade :Gradeid
      -- 多一个:Gradeid。:Hgrade 是接收成绩的主变量,:Gradeid 就是它的指示变量
      FROM SC
      WHERE Sno = :givensno AND Cno = :givencno;
      -- 如果数据库里 Grade 不是空值 → Gradeid = 0,可以直接用 Hgrade 的值
      -- 如果数据库里 Grade 是 NULL → Gradeid = -1,说明 Hgrade 里的值是无效的,不能直接用
      gra_ind = -1 ; -- 要把数据库里的值改成 NULL
      EXEC SQL UPDATE SC
      SET Grade = :Hgrade INDICATOR :gra_ind
      -- 把 Grade 字段的值设置成 :Hgrade,但要首先参考指示变量 gra_ind
      -- 数据库会忽略 :Hgrade 里的数字,直接把 Grade 设为 NULL
      WHERE cno = :givencno; -- 根据学号查找
    • 为了使用主语言变量,必须首先在DECLARE SECTION部分声明这些变量
      Why? 编译时类型检查、预先申请内存空间。只有在declare section中定义的主语言变量才能被用在ESQL中

      exec sql begin declare section; -- 主变量声明开始
      char hsno[10],givensno[10], hsname[21];
      int hsage;
      exec sql end declare section; -- 主变量生声明结束
      EXEC SQL select Sno, Sname, Sage
      into :hsno, :hsname, :hsage
      from Student
      where Sno = :givensno ; --根据学号查询学号、姓名、年龄
  5. ⭐游标 Cursor#

    游标是系统为用户开设的一个数据缓冲区,用于存放SQL查询的执行结果。解决SQL批量返回数据、主语言单条处理之间的矛盾

    • 声明游标 EXEC SQL DECLARE 游标名 CURSOR FOR 查询语句;
    • 打开游标 EXEC SQL OPEN 游标名;
    • 提取数据 EXEC SQL FETCH 游标名 INTO 主变量;
    • 关闭游标 EXEC SQL CLOSE 游标名;
  6. 过程#

  • 建立/关闭数据库连接
    EXEC SQL CONNECT TO target [AS 连接名] [USER 用户名]; -- 建立连接
    EXEC SQL SET CONNECTION 连接名 | DEFAULT; -- 切换连接
    EXEC SQL DISCONNECT 连接名 | DEFAULT; -- 关闭连接
  • 例 依次检查某个系的学生记录,交互式更新某些学生年龄。
    EXEC SQL BEGIN DECLARE SECTION; /*主变量声明开始*/
    char Deptname[21];
    char Hsno[10];
    char Hsname[21];
    char Hssex[3];
    int HSage;
    int NEWAGE;
    EXEC SQL END DECLARE SECTION; /*主变量声明结束*/
    long SQLCODE;
    EXEC SQL INCLUDE SQLCA; /*定义SQL通信区*/
    #include <sqlca.h>
    int main(void) /*C语言主程序开始*/
    {
    int count = 0;
    char yn; /*变量yn代表yes或no*/
    printf("Please choose the department name(CS/MA/IS): ");
    scanf("%s",deptname); /*为主变量deptname赋值*/
    EXEC SQL CONNECT TO TEST@localhost:54321 USER "SYSTEM"/"MANAGER"; /*连接数据库TEST*/
    -- 我现在要登录连接到数据库,数据库地址是本机,端口是 54321,数据库名字叫 TEST,登录账号是 SYSTEM,密码是 MANAGER
    EXEC SQL DECLARE SX CURSOR FOR /*定义游标SX*/
    SELECT Sno,Sname,Ssex,Sage /*游标SX对应的查询语句*/
    FROM Student
    WHERE SDept = :deptname;
    EXEC SQL OPEN SX;
    /*打开游标SX,执行游标对应的查询,并指向查询结果的第一行*/
    for (;;) -- 循环读取游标里的每一条数据,直到游标读完 / 出错时退出
    {
    /* 推进游标,将当前数据放入主变量 */
    EXEC SQL FETCH SX INTO :Hsno, :Hsname, :Hssex, :HSage;
    if (sqlca.sqlcode != 0) { -- 操作不成功时退出
    break;
    }
    /* 是第一行的话,打印表头和学生信息 */
    if (count++ == 0) {
    printf("\n%-10s %-20s %-10s %-10s\n", "Sno", "Sname", "Ssex", "Sage");
    }
    /* 打印当前学生信息 */
    printf("%-10s %-20s %-10s %-10d\n", Hsno, Hsname, Hssex, HSage);
    /* 询问用户是否要更新该学生的年龄 */
    printf("UPDATE AGE(y/n)? ");
    do {
    scanf("%c", &yn);
    -- getchar(); --吃掉多余的换行符
    } while (yn != 'N' && yn != 'n' && yn != 'Y' && yn != 'y');
    -- 强制让用户必须输入 Y/y/ N/n 才往下走,输错就一直重新输
    /* 如果选择更新操作 */
    if (yn == 'y' || yn == 'Y') {
    printf("INPUT NEW AGE: ");
    scanf("%d", &NEWAGE);
    getchar();
    /* 嵌入式SQL更新语句*/
    EXEC SQL UPDATE Student
    SET Sage = :NEWAGE -- Sage更新为读入的NWEAGE
    WHERE CURRENT OF SX;
    } /* 对当前游标指向的学生年龄进行更新 */
    }
    /* 收尾 */
    EXEC SQL CLOSE SX; -- 关闭游标SX,不再和查询结果对应
    EXEC SQL COMMIT WORK; -- 提交更新
    EXEC SQL DISCONNECT TEST; -- 断开数据库连接
    } -- 只在 EXEC SQL FETCH SX INTO 语句之后检查了状态码 SQLCA.SQLCODE
    -- 在其他嵌入式SQL语句之后,都没有检查SQL语句的执行状态码!
    -- Solution:添加异常处理👇

异常处理#

  1. whenever是嵌入式SQL的全局异常捕获机制
    EXEC SQL WHENEVER 条件 动作;
    预编译器在处理过程中,会根据WHENEVER语句的定义,在每一条嵌入式SQL语句之后添加下面的异常状态检查命令: if ( condition ) { action }
  2. 常见执行异常
    SQLERROR、NOT FOUND、SQLWARNING
  3. 处理方法 CONTINUE、GOTO、STOP、DO function | BREAK | CONTINUE
  4. 例
    exec sql whenever sqlerror goto report_error ;
    exec sql whenever not found goto notfound ;

不用游标的SQL语句#

  • 说明性语句、数据定义 / 控制语句
    -- 1. 主变量声明(必须用固定段包裹)
    EXEC SQL BEGIN DECLARE SECTION;
    char givensno[10];
    char hsno[10], hsname[21];
    EXEC SQL END DECLARE SECTION;
    -- 2. 定义SQL通信区(获取SQL执行状态)
    EXEC SQL INCLUDE SQLCA;
    -- 3. 异常处理声明(出错跳转、无数据跳转)
    EXEC SQL WHENEVER SQLERROR GOTO error_handle;
    EXEC SQL WHENEVER NOT FOUND GOTO no_ data;
    -- 创建学生表 CREATE
    EXEC SQL CREATE TABLE Student (
    Sno CHAR(9) PRIMARY KEY,
    Sname CHAR(20) NOT NULL,
    Sage SMALLINT,
    Sdept CHAR(20)
    );
    --删除表DROP
    EXEC SQL DROP TABLE TEST;
    -- 修改ALTER:为Student表添加手机号字段
    EXEC SQL ALTER TABLE Student ADD Sphone CHAR(11);
    -- 授权:给用户user1授予Student表的查询、修改权限
    EXEC SQL GRANT SELECT, UPDATE ON Student TO user1;
    -- 回收user1对Student表的修改权限
    EXEC SQL REVOKE UPDATE ON Student FROM user1;
    -- 事务控制:提交数据库更新(如增删改)
    EXEC SQL COMMIT WORK;
  • 单条结果查询:SELECT … INTO …
    EXEC SQL SELECT Sno,Cno,Grade
    INTO :Hsno, :Hname, :Hcno, :Hgrade, :Gradeid /* 指示变量Gradeid */
    FROM SC
    WHERE Sno = :givensno AND Cno = :givencno;
    if(Gradeid < 0){
    …… -- 学生givensno在课程givencno上的成绩为空值
    }else{
    ……
    }
  • 普通增删改(非 CURRENT 形式的 INSERT、DELETE、UPDATE)
    增:某个学生新选修了某门课程,将有关记录插入SC表中。假设插入的学号已赋给主变量stdno,课程号已赋给主变量couno。
    gradeid = −1; /* gradeid为指示变量 */
    EXEC SQL INSERT
    INTO SC(Sno, Cno, Grade)
    VALUES(:stdno, :couno, :gr :gradeid);

使用游标的SQL语句#

  • 使用语句多条结果的 SELECT 查询、CURRENT 形式的 UPDATE/DELETE 语句
  • 游标(Cursor)的使用操作
    1. 声明游标 EXEC SQL DECLARE 游标名 CURSOR FOR 查询语句;
    2. 打开游标 EXEC SQL OPEN 游标名;
    3. 提取数据 EXEC SQL FETCH 游标名 INTO 主变量;
    4. 关闭游标 EXEC SQL CLOSE 游标名;
  • 可滚动游标 SCROLL
    -- 加SCROLL
    EXEC SQL DECLARE agent_dollars SCROLL CURSOR FOR
    SELECT aid, sum(dollars)
    FROM orders
    WHERE cid = :cust_id
    GROUP BY aid;
    EXEC SQL OPEN agent_dollars;
    EXEC SQL FETCH FIRST agent_dollars INTO :agent_id,:dollar_sum;
    EXEC SQL FETCH LAST agent_dollars INTO :agent_id,:dollar_sum;
    EXEC SQL FETCH PRIOR agent_dollars INTO :agent_id,:dollar_sum; -- 上一个
    EXEC SQL FETCH NEXT agent_dollars INTO :agent_id,:dollar_sum; -- 下一个
  • 例
    EXEC SQL INCLUDE SQLCA; --定义SQL状态区
    -- 声明主变量
    EXEC SQL BEGIN DECLARE SECTION;
    char cust_id[10];
    char agent_id[10];
    float dollar_sum;
    EXEC SQL END DECLARE SECTION;
    -- 声明异常处理(必须写在最前面!)
    EXEC SQL WHENEVER NOT FOUND GOTO finish;
    /* 声明游标 agent_dollars */
    EXEC SQL DECLARE agent_dollars CURSOR FOR
    SELECT aid,sum(dollars)
    FROM orders
    WHERE cid=:cust_id
    GROUP BY aid;
    /* 打开游标 */
    EXEC SQL OPEN agent_dollars;
    /* 提取数据 */
    while (TRUE) {
    EXEC SQL FETCH agent_dollars INTO :agent_id, :dollar_sum;
    -- 推动游标指针至下一条记录,同时将当前记录取出来送至主变量
    printf("%s %11.2f\n", agent_id, dollar_sum);
    }
    /* 关闭游标 */
    finish: EXEC SQL CLOSE agent_dollars;
  • CURRENT 形式的 UPDATE/DELETE 语句#

需要对查询结果集做差异化修改(如有的行改、有的不改、有的改的数值不同),而不是批量UPDATE/DELETE WHERE CURRENT OF 游标名

EXEC SQL DECLARE SX CURSOR FOR
SELECT Sno,Sname,Ssex,Sage
FROM Student
WHERE Sdept=:deptname;
EXEC SQL OPEN SX;
for(;;){
EXEC SQL FETCH SX INTO :HSno,:Hname,:HSsex,:HSage;
if (SQLCA.SQLCODE != 0) break; -- 操作不成功,则退出循环
……
EXEC SQL UPDATE Student
SET Sage=:NEWAGE
WHERE CURRENT OF SX; -- 只对当前游标指向的一行记录
……
}
EXEC SQL CLOSE SX;

动态SQL#

  1. 使用SQL语句主变量
    程序主变量包含的内容是SQL语句的内容**
    EXEC SQL BEGIN DECLARE SECTION;
    const char *stmt = "CREATE TABLE test(a int);";
    -- 定义了一个字符串指针变量stmt,内容是一条完整的 SQL 语句文本
    -- CREATE TABLE test(a int);(功能是创建一张名为test的表,包含一个int类型的列a)
    const char *stmt = "CREATE TABLE student(sno char(9), sname char(20));";
    -- 或者这么写
    EXEC SQL END DECLARE SECTION;
    /* 执行动态SQL语句,可以动态创建TABLE */
    EXEC SQL EXECUTE IMMEDIATE :stmt;
  2. 动态参数
    用?当占位符
  3. 执行准备好的语句(EXECUTE)
    EXEC SQL BEGIN DECLARE SECTION;
    const char *stmt="INSERT INTO test VALUES(?);";-- 动态参数
    EXEC SQL END DECLARE SECTION;
    /* 准备语句 */
    EXEC SQL PREPARE mystmt FROM :stmt;
    /*执行INSERT语句,设定参数为100*/
    EXEC SQL EXECUTE mystmt USING 100;

过程化SQL#

  1. what?写在数据库中的带编程逻辑的SQL语言,可用于定义触发器、存储过程、存储函数对应的SQL程序块。
  2. 过程化SQL vs 嵌入式SQL
    可独立编程,不再需要区分 主变量 与 SQL变量
    不需要经历从预编译到编译的处理
    在数据库服务器内部实现数据交换与处理
  3. 常用的两种过程化SQL:Oracle:PL/SQL;SQL Server:T-SQL

过程化SQL的块结构#

  1. 过程化SQL的基本单位是块 Block
  2. 块结构拆解
    • 定义部分(DECLARE)
      声明局部变量、常量、游标、自定义异常
    DECLARE
    v_sname CHAR(20); -- 变量
    v_age CONSTANT INT := 18; -- 常量
    CURSOR c_stu IS SELECT Sname FROM Student; -- 游标
    e_age_too_old EXCEPTION; -- 自定义异常
    • 执行部分(BEGIN…END)
    BEGIN
    -- 正常执行的逻辑
    SELECT Sname INTO v_sname FROM Student WHERE Sno = '241880543';
    IF v_age > 30 THEN
    RAISE e_age_too_old; -- 抛出自定义异常
    END IF;
    EXCEPTION
    WHEN NO_DATA_FOUND THEN
    DBMS_OUTPUT.PUT_LINE('未找到该学生!');
    WHEN e_age_too_old THEN
    DBMS_OUTPUT.PUT_LINE('年龄超过限制!');
    WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE('发生未知错误:' || SQLERRM);
    END;

PL/SQL变量和常量的定义#

  1. 变量定义
    • 基本数据结构 Number、Char、Date、Long、Boolean、Varchar2
    • 注意:
      char h_sno[10] = "211210166"; // 对应 char(9),需 n+1 长度
    • 例
    DECLARE
    -- ① 无初值、允许为NULL(PPT里的基础形式)
    v_name VARCHAR2(20); -- 变长字符型,最大为4000个字符/Char 字符型,最大2000个字符
    -- ② 带NOT NULL + 用:=赋值(语法1,严格按PPT)
    v_age NUMBER(3) NOT NULL := 18;
    -- ③ 带NOT NULL + 用DEFAULT赋值(等价于PPT的语法2,效果和:=完全一致)
    v_score NUMBER NOT NULL DEFAULT 60;
    BEGIN
    -- 赋值语句
    v_name := '张三';
    END;
  2. 常量定义

流程控制#


存储过程和函数#

数据管理基础
https://lilyly9.github.io/posts/数据管理基础/
作者
Stari
发布于
2026-03-04
许可协议
CC BY-NC-SA 4.0