当前位置: 首页 > news >正文

数据库概论速成期中版

文章目录

  • 引论
    • 数据库用户
      • Casual users
      • Naive users
      • Application programmers
      • Database administrators
  • 关系模型
    • CAP数据库
    • 两种描述关系数据库的方式
      • 简单总结
    • 第一范式规则
    • 第二范式规则
      • 举个例子
        • 符合第二规则的操作
        • 不符合第二规则的操作
    • 第三范式规则
    • key,superkey,null values,主键,候选键
      • 1. 什么是Keys(键)?
      • 2. 什么是Superkeys(超键)?
      • 3. 什么是Null Values(空值)?
      • 4. 什么是主键(Primary Key)?
      • 5. 什么是候选键?
    • 集合运算
      • 1. **并(Union)**
      • 2. **交(Intersection)**
      • 3. **差(Difference)**
      • 4. **笛卡尔积(Cartesian Product)**
      • 5. **投影(Projection)**
      • 6. **选择(Selection)**
      • 7. **自然连接(Natural Join)**
      • 8. **除(Division)**
  • sql语言查询
    • DDL
      • 1. **主要功能**
      • 2. **常见 DDL 语句**
        • (1) **CREATE** - 创建数据库对象
        • (2) **ALTER** - 修改数据库对象
        • (3) **DROP** - 删除数据库对象
        • (4) **TRUNCATE** - 清空表数据
      • 3. **特点**
    • 数据类型
      • 实体完整性规则和参照完整性规则
      • 1. **实体完整性规则**(Entity Integrity Rule)
      • 2. **参照完整性规则**(Referential Integrity Rule)
    • 相关语句
      • count
      • sum
      • avg
      • max,min
      • group by
        • 需求:只看人数大于 1 的班级
      • order by
      • into
      • in
        • 相关子查询
        • 子查询比较关键词
      • join
        • **INNER JOIN**(默认 JOIN)
        • **LEFT JOIN**(LEFT OUTER JOIN)
        • **RIGHT JOIN**(RIGHT OUTER JOIN)
        • **FULL JOIN**(FULL OUTER JOIN)
        • **CROSS JOIN**(交叉连接)
      • exists
      • union
        • INTERSECT 运算符
        • EXCEPT运算符
    • 联接查询
      • 等值联接
      • 自然联接
      • 非等值连接
      • 自身连接
      • 外联接
      • 复合条件联接
    • update
    • delete
    • 索引
      • 唯一索引 (Unique Index)
      • 聚集索引(CLUSTERED INDEX)
      • 非簇索引 (Nonclustered Index)
  • 存储程序和触发器
    • 存储过程
      • 啥是 Stored Procedure(存储过程)?
    • 触发器
      • 啥是触发器?
      • 触发器的类型
      • 啥是 inserted 和 deleted 表?
      • 它们在啥时候有数据?
  • 数据库设计
      • 数据库设计是啥?
    • 概念模型设计(基于 E-R 图)
    • 范式设计(基于规范化理论)
      • 啥是依赖?
    • ER相关概念
        • 单值 (Single-Valued) 和 多值 (Multi-Valued)
      • 对方实体 (Other Entity)
        • max-card(E, R)(最大基数)
        • min-card(E, R)(最小基数)
      • 二元关系转换
    • 弱实体
      • 啥是弱实体?
      • 啥是泛化层次结构?
        • 约束条件
    • 函数依赖
      • 先复习:啥是函数依赖?
        • Armstrong 公理(三大基本规则)
          • (1) 自反律 (Reflexivity Rule)
          • (2) 增补律 (Augmentation Rule)
          • (3) 传递律 (Transitivity Rule)
          • (1) 并规则 (Union Rule)
          • (2) 分解规则 (Decomposition Rule)
          • (3) 伪传递律 (Pseudo-Transitivity Rule)
        • 闭包 (Closure) 的概念
      • 覆盖和最小覆盖
        • 1. 啥是覆盖 (Cover)?
        • 2. 啥是最小覆盖 (Minimal Cover)?
      • 求最小覆盖的步骤
        • 步骤 1:分解右边(单属性化)
        • 步骤 2:去掉冗余属性(简化左边)
        • 步骤 3:去掉冗余依赖
        • 最终最小覆盖:
      • 再来个复杂点的例子
      • 关系模式的分解
      • 关系模式分解的两个关键性质
        • 1. 无损连接 (Lossless Join)
        • 2. 依赖保持 (Dependency Preservation)
  • 完整性约束,视图,安全,系统目录
        • 完整性约束 (Integrity Constraints)
        • 视图 (Views)
        • 安全 (Security)
      • 数据库安全的四个等级
        • 1. 系统级安全 (System-Level Security)
        • 2. 数据库级安全 (Database-Level Security)
        • 3. 对象级安全 (Object-Level Security)
        • 数据级安全 (Data-Level Security)
        • 系统目录 (System Catalogs)
  • 练习题
      • 文件系统和DBMS的四个主要区别
      • 解释物理独立性,以及它在数据库系统中的重要性。
      • 找出候选键

  • 根据笔者的学习过程的记录,如果你的学校所学内容与这些不符合,没必要花大精力在上面。

引论

数据库用户

Casual users

临时用户,对sql语言有一定了解并能查询

Naive users

本地用户,通过菜单应用程序执行sql,无需sql语句

Application programmers

应用程序员,负责编写本地用户使用的程序

Database administrators

数据库管理员,负责设计和维护数据库的专业人员

工作包括:

  • 创建数据库
  • 创建表格
  • 执行幕后任务
  • 页面的物理布局

关系模型

CAP数据库

image-20250426210243295

两种描述关系数据库的方式

在关系型数据库里,描述数据的方式有两套术语,虽然说的是一回事,但名字听起来有点不同:

  1. 第一套术语:表(Tables)、列(Columns)、行(Rows)
    • 表(Tables):就像一张Excel表格,里面装了一堆数据。比如“学生表”存了所有学生的信息。
    • 列(Columns):表里的每一列,就像Excel的标题,比如“姓名”“学号”“年龄”,每列存一种信息。
    • 行(Rows):表里的每一行,就是一条具体的数据记录。比如“张伟, 001, 18”是一行,代表一个学生的信息。
  2. 第二套术语:关系(Relations)、元组(Tuples)、属性(Attributes)
    • 关系(Relations):其实就是“表”的学名。因为表里的数据是通过“关系”组织起来的,所以叫关系。跟“表”是一个意思。
    • 元组(Tuples):就是“行”的学名。每行数据是一个完整的记录,数学上叫“元组”。比如“张伟, 001, 18”就是一个元组。
    • 属性(Attributes):就是“列”的学名。每列表示数据的一个特性,数学上叫“属性”。比如“姓名”“学号”就是属性。

简单总结

  • 表 = 关系:都是指整个表格。
  • 行 = 元组:都是指表格里的一条记录。
  • 列 = 属性:都是指表格里的一个字段(标题)。

第一范式规则

第一范式是关系型数据库的一个基本规则,它要求表的每一列(字段)里的数据必须是单一的、不可再分的原子值。换句话说:

  • 不能在一列里塞多个值(比如一个格子里放一堆东西)。
  • 不能让一列的值有复杂的内部结构(比如嵌套一个表格或记录)。

只有满足这个要求的表,才算是达到了第一范式。

要满足1NF,如果一个格子内的属性是同一标签,得把多值拆开,让每列只存单一值。

假如有个表这样:

学号姓名联系方式
001张伟电话:123456, 邮箱:zw@xx.com
002李明电话:789012, 邮箱:lm@yy.com

联系方式列有内部结构(电话和邮箱混在一起),不符合1NF。改成1NF可以拆成两列:

学号姓名电话邮箱
001张伟123456zw@xx.com
002李明789012lm@yy.com

第二范式规则

这个规则说,在关系型数据库里,你想找表里的某一行数据(记录),只能通过行里的内容(也就是每一列的具体值)来查找。换句话说,你得告诉数据库“我要找哪些值”,而不是靠其他方式(比如行的位置或顺序)来挑数据。

举个例子

假设你有一个学生表:

学号姓名年龄
001张伟18
002李明19
003王芳18
符合第二规则的操作

如果你想找某个学生,可以用列里的值作为条件,比如:

  • “找出姓名是‘张伟’的行” → 数据库返回:001, 张伟, 18。
  • “找出学号是‘002’的行” → 数据库返回:002, 李明, 19。
  • “找出年龄是18的行” → 数据库返回:001, 张伟, 18 和 003, 王芳, 18。

这些操作都是通过内容(学号、姓名、年龄的具体值)来找数据,符合第二规则。

不符合第二规则的操作

如果你说:

  • “给我表里第2行的数据” → 数据库会说“啥?不行!” 因为它不认行的位置。
  • “给我按插入顺序的第1条数据” → 也不行,因为数据库不关心数据插入的顺序。

为什么不行?因为数据库里的行可能会因为排序、分布式存储或其他原因,位置随时变。如果靠位置找数据,结果可能不靠谱。

第三范式规则

第三规则说,在关系型数据库的同一个表里,不能有两行数据完全一模一样。也就是说,表里的每一行(元组)在所有列的值上都得是独一无二的,不能有“双胞胎”行。

在实际中,这通常靠主键(Primary Key)来保证。主键是一列(或几列),它的值在每行都不同,用来区分每一行。

key,superkey,null values,主键,候选键

1. 什么是Keys(键)?

键是数据库表中用来唯一标识一行数据建立表之间关系的列(或几列)。它就像一个“标签”,让数据库能快速找到或区分特定的行。

  • 作用
    • 确保每行数据独一无二(区分行)。
    • 帮助表之间建立联系(比如通过外键)。
  • 例子:在一个学生表里,“学号”可以是键,因为每个学生的学号都不一样,能用来找特定学生。

2. 什么是Superkeys(超键)?

超键是能唯一标识表中每一行的列的集合,可以包含一列或多列。简单说,超键是“够用”的键,可能包含了比实际需要更多的列。

  • 特点

    • 超键只要能保证每行唯一就行,哪怕包含了不必要的列。
    • 超键可能有很多个。
  • 例子

    假设学生表有这些列:

    学号,姓名, 年龄

    • {学号} 是一个超键,因为学号本身就能唯一标识每行。
    • {学号, 姓名} 也是超键,因为学号加姓名肯定也能唯一标识(虽然姓名其实没必要)。
    • {学号, 姓名, 年龄} 还是超键,包含了所有列,肯定唯一。

但超键可能“太胖”,包含多余的列,所以我们会从中挑出更精简的键(比如候选键或主键)。

3. 什么是Null Values(空值)?

空值(Null)表示数据缺失或未知,不是0,也不是空字符串,而是一个特殊的标记,表示“这里没值”。

4. 什么是主键(Primary Key)?

主键是表中唯一标识每一行的列(或几列),是从超键中挑出来的一个最精简、最合适的键。每个表只能有一个主键。

  • 特点
    • 唯一性:主键的值在每行都不同,不能重复。
    • 非空:主键列不能有空值(Null)。
    • 唯一选择:一个表只能定一个主键。
  • 作用
    • 区分表中的每一行(像身份证号)。
    • 作为其他表的外键,建立表之间的关系。

5. 什么是候选键?

候选键是关系型数据库中能唯一标识表中每一行的列(或列的组合),而且是最精简的。换句话说,它是“够用且不浪费”的键,能保证每行不重复,但没有多余的列。

  • 特点
    • 唯一性:候选键的值在每行都不同,不能重复。
    • 非空:候选键的列不能有空值(Null)。
    • 最精简:不能去掉任何一列,否则就没法唯一标识行了。
    • 一个表可以有多个候选键,但最终只会选一个作为主键
  • 和超键的区别
    • 超键(Superkey)可能包含多余的列,比如“学号+姓名”也能唯一标识,但“姓名”其实没必要。
    • 候选键是超键的“瘦身版”,只保留最必要的列。
  • 和主键的区别
    • 候选键是“候选人”,表里可能有好几个。
    • 主键是从候选键中挑一个“上岗”的,只有一个。

集合运算

img

  • 表 R (学生信息)

    学号 (ID)姓名 (Name)
    1张三
    2李四
    3王五
  • 表 S (选课信息)

    学号 (ID)姓名 (Name)
    2李四
    4赵六

1. 并(Union)

  • 定义:合并 R 和 S的所有元组,去除重复。

  • 操作 R ∪ S R∪S RS

  • 结果

    学号 (ID)姓名 (Name)
    1张三
    2李四
    3王五
    4赵六
SELECT * FROM R
UNION
SELECT * FROM S;

2. 交(Intersection)

  • 定义:返回 R 和 S 共有的元组。

  • 操作:R ∩ S

  • 结果

    学号 (ID)姓名 (Name)
    2李四
SELECT R.* FROM R
INNER JOIN S ON R.ID = S.ID AND R.Name = S.Name;

3. 差(Difference)

  • 定义:返回在 R 中但不在 S 中的元组。

  • 操作:R−S

  • 结果

    学号 (ID)姓名 (Name)
    1张三
    3王五

4. 笛卡尔积(Cartesian Product)

  • 定义:将 R 和 S 的每对元组组合。

  • 操作:R×S

  • 结果

    R.IDR.NameS.IDS.Name
    1张三2李四
    1张三4赵六
    2李四2李四
SELECT * FROM R CROSS JOIN S;

5. 投影(Projection)

  • 定义:从 R 中选择“姓名”列,去除重复。

  • 操作 π N a m e ( R ) πName(R) πName(R)

  • 结果

    姓名 (Name)
    张三
    李四
    王五
  • SQL

    SELECT DISTINCT Name FROM R;

  • 说明:仅返回唯一的姓名。

6. 选择(Selection)

  • 定义:从 R 中选择学号大于 1 的元组。

  • 操作 σ I D > 1 ( R ) σID>1(R) σID>1(R)

  • 结果

    学号 (ID)姓名 (Name)
    2李四
    3王五

7. 自然连接(Natural Join)

  • 定义:按同名属性(ID 和 Name)连接 R 和 S 。

  • 操作 R ⋈ S R⋈S RS

  • 结果

    学号 (ID)姓名 (Name)
    2李四
  • SQL

    SELECT * FROM R NATURAL JOIN S;

  • 说明:只保留 ID 和 Name 均相等的元组。

8. 除(Division)

  • 场景:假设新表T

    记录学生选课:

    • 表 T (选课记录)

      学号 (ID)课程 (Course)
      1数学
      1英语
      2数学
    • 表 U (必修课)

      课程 (Course)
      数学
      英语
  • 定义:找出选修了 U 中所有课程的学生。

  • 操作 T ÷ U T÷U T÷U

  • 结果

    学号 (ID)
    1
    SELECT ID FROM T
    GROUP BY ID
    HAVING COUNT(DISTINCT Course) = (SELECT COUNT(*) FROM U)
    AND NOT EXISTS (SELECT Course FROM UWHERE Course NOT IN (SELECT Course FROM T WHERE T.ID = T.ID)
    );
    

sql语言查询

DDL

SQL 的 DDL(Data Definition Language,数据定义语言) 用于定义和管理数据库结构,包括创建、修改、删除数据库对象(如表、视图、索引等)。DDL 语句主要操作数据库的模式(Schema),不涉及数据内容操作。以下是 DDL 的简单介绍及常见语句:

1. 主要功能

  • 创建数据库对象(如表、数据库、索引)。
  • 修改现有对象的结构(如添加列、修改数据类型)。
  • 删除对象(如删除表、视图)。
  • 定义约束(如主键、外键、唯一约束)。

2. 常见 DDL 语句

(1) CREATE - 创建数据库对象
  • 用途:创建数据库、表、视图、索引等。

  • 示例

    -- 创建数据库 CREATE DATABASE school; -- 创建表 CREATE TABLE students ( id INT PRIMARY KEY, name VARCHAR(50) NOT NULL, age INT );

  • 说明:定义表结构,指定列名、数据类型和约束(如 PRIMARY KEY、NOT NULL)。

(2) ALTER - 修改数据库对象
  • 用途:修改表结构,如添加列、删除列、更改数据类型等。

  • 示例

    -- 添加列 ALTER TABLE students ADD email VARCHAR(100); -- 修改列数据类型 ALTER TABLE students MODIFY age SMALLINT; -- 删除列 ALTER TABLE students DROP COLUMN email;

  • 说明:用于调整已有对象的定义。

  • 在sql-server中添加列不需要添加列名,但删除需要

(3) DROP - 删除数据库对象
  • 用途:删除表、数据库、索引等。

  • 示例

    -- 删除表 DROP TABLE students; -- 删除数据库 DROP DATABASE school;

  • 说明:删除操作不可恢复,需谨慎使用。

(4) TRUNCATE - 清空表数据
  • 用途:删除表中所有数据,但保留表结构。

  • 示例

    TRUNCATE TABLE students;

  • 说明:与 DELETE 不同,TRUNCATE 不记录日志,执行更快,但无法回滚。

3. 特点

  • 自动提交:DDL 语句执行后自动提交(COMMIT),无法回滚(ROLLBACK)。
  • 结构操作:只操作数据库或表的结构,不涉及数据内容(数据操作由 DML 负责)。
  • 权限要求:通常需要较高的权限(如管理员权限)来执行 DDL。

数据类型

数据类型描述示例值适用场景
INT整数(通常 4 字节,范围约 -2^31 到 2^31-1)123, -456存储整数,如 ID、年龄
BIGINT大整数(通常 8 字节,范围更大)123456789012存储大范围整数,如计数器
FLOAT单精度浮点数(近似值)3.14, -0.001存储小数,精度要求不高
DOUBLE双精度浮点数(更高精度)3.1415926535存储高精度小数,如科学计算
DECIMAL(m,d)定点小数(m 位总长度,d 位小数)123.45 (DECIMAL(5,2))存储精确小数,如货币金额
CHAR(n)固定长度字符串,最大 n 个字符"ABC " (CHAR(5))固定长度文本,如状态码、邮编
VARCHAR(n)可变长度字符串,最大 n 个字符“ABC” (VARCHAR(5))可变长度文本,如姓名、地址
TEXT大文本数据,无固定长度限制(视数据库而定)“This is a long text…”存储大段文本,如文章、描述
DATE日期(年-月-日)2023-04-27存储日期,如生日、注册日期
DATETIME日期和时间2023-04-27 14:30:00存储时间戳,如创建时间
BOOLEAN布尔值(真/假)TRUE, FALSE存储开关状态,如启用/禁用
BLOB二进制大对象,用于存储二进制数据图像、文件数据存储图片、视频等二进制文件

varchar和char的区别在于,varchar占用的存储空间是根据当前字符长度动态申请的,加上一个数据长度标识符,优点是节约空间,缺点是查找时需要通过标识符进行一定的计算,会比char略慢。

实体完整性规则和参照完整性规则

1. 实体完整性规则(Entity Integrity Rule)

啥意思?

  • 实体完整性是保证数据库里每条记录(行)都有一个唯一标识,而且这个标识不能是空的。简单说,就是每行数据得有个“身份证号”,而且不能缺。

咋做到?

  • 主要靠

    主键(Primary Key)

    • 每张表的主键列(比如 id)必须唯一,不能有两行数据的主键值一样。
    • 主键列不能是 NULL(空值),因为 NULL 代表“不知道”,没法当标识。

2. 参照完整性规则(Referential Integrity Rule)

啥意思?

  • 参照完整性是保证表之间的关系靠谱。简单说,如果一张表里的某个值(外键)引用了另一张表的数据,那引用的值必须在另一张表里真实存在,或者是空的。

咋做到?

  • 靠**外键(Foreign Key)**约束:
    • 外键列的值要么是主表中主键的合法值,要么是 NULL。
    • 如果主表的数据被删了或改了,子表的外键得跟着调整(比如删除、置空,或禁止操作)。

为啥重要?

  • 防止“孤儿数据”。比如,订单表里的 customer_id 必须对应客户表里存在的客户,不然订单就不知道是谁的了。

3.用户定义完整性

录入的数据必须在用户定义的范围内

相关语句

插入多条数据

insert into test values('2','enoch',19),('3','llk',20);

去重选择

select distinct name from test;

选择前几条记录,order默认从小到大排序

select top 4 * from test order by age;

image-20250427201133193

count

用 test 表来试试:

SELECT     COUNT(*) AS 总行数,    COUNT(phone) AS phone列非空个数,    COUNT(DISTINCT phone) AS phone列不重复个数 
FROM test;

结果

总行数 | phone列非空个数 | phone列不重复个数  
2     | 2             | 2

sum

SELECT SUM(distinct CAST(id AS INT)) AS id总和
FROM test;

cast函数将字符转为数字,去重后求和

avg

求平均值

SELECT AVG(id) AS id平均值,AVG(DISTINCT id) AS id不重复平均值
FROM test;

max,min

同理

image-20250427202156228

group by

需求:只看人数大于 1 的班级
SELECT 
class_id, COUNT(*) AS 人数 
FROM test 
GROUP BY class_id 
HAVING COUNT(*) > 1;

结果

class_id | 人数
---------|------
1        | 2
2        | 2

咋算的?

  • 先按 class_id 分组:1 班 2 人,2 班 2 人,3 班 1 人。
  • HAVING COUNT(*) > 1 筛选,只留下人数大于 1 的组,所以 3 班被过滤掉了。

group by,相当于把之前的表按照一定的限制条件分成更小的几个表,count函数在这些小表中分别执行

image-20250427202758152

order by

select * from test order by grade desc

改为从大到小排序(默认是升序

into

select * from test into new_table

将查询数据输出到新表中

in

... in (select ...)

in找集合里的东西,()中是子查询

作用域问题,主查询和子查询看不到对方执行查询的列的细节,只能看到执行后返回的结果

相关子查询

子查询需要依赖主查询中的一些数据

SELECT name, class_id,(SELECT COUNT(*) FROM test t2 WHERE t2.class_id = t1.class_id) AS 班级人数
FROM test t1;

通过建立别名,每次都拿到外围的t1.class_id作为限制条件

子查询比较关键词
列名 比较符 (ANY|ALL) (子查询)
  • 列名:你要比较的值(比如 id)。
  • 比较符:像 >、<、>= 啥的。
  • 子查询:返回一堆值(比如一列 id)。
  • ANY/SOME:ANY 和 SOME 是一个意思(SQL Server 里一样),表示“跟子查询里的任意一个值比”。
  • ALL:表示“跟子查询里的所有值比”。

eg.

SELECT name
FROM test
WHERE id > ANY (SELECT min_id FROM classes);

join

SELECT t.name
FROM test t
JOIN classes c ON t.id > c.min_id;

这句 SQL 是在查 test 表和 classes 表,挑出 test 表里的 name,但有个条件:test 表里的 id 要大于 classes 表里的 min_id。

简单说,就是找“学生 ID 比某些班级的 min_id 大的学生名字”。每一行对应匹配

  • JOIN 是 SQL 里的“连表神器”,专门把两张表(或更多)按条件拼起来,生成新的结果。

  • 就像你有两个名单,一个是学生名单(test),一个是班级名单(classes),你想把学生的班级信息拼到一起,JOIN 就能干这活儿。

  1. INNER JOIN(默认 JOIN)

    只保留两张表里满足 ON 条件的行,不满足的直接扔掉。

    就像找“既是学生又有班级信息的记录”,不匹配的就不管。

SELECT t.name, c.class_name
FROM test t
INNER JOIN classes c ON t.class_id = c.class_id;
  1. LEFT JOIN(LEFT OUTER JOIN)

保留左表(test)的所有行,右表(classes)匹配不上的就填 NULL。

就像“所有学生都列出来,找不到班级的就写空”。

name  | class_name
------|------------
enoch | Class A
lally | Class A
alice | Class B
bob   | Class B
cathy | NULL
  1. RIGHT JOIN(RIGHT OUTER JOIN)

保留右表(classes)的所有行,左表(test)匹配不上的填 NULL。

就像“所有班级都列出来,找不到学生的就写空”。

nameclass_name
enochClass A
lallyClass A
aliceClass B
bobClass B
cathyClass C
NULLClass D
  1. FULL JOIN(FULL OUTER JOIN)

两边表的所有行都保留,匹配不上的填 NULL。

就像“学生和班级都列出来,找不到对应信息的就写空”。

  1. CROSS JOIN(交叉连接)

不写 ON 条件,把两张表每行都组合一次,生成“笛卡尔积”。test 有 5 行,classes 有 4 行,生成 5 × 4 = 20 行:

exists

简单说

  • EXISTS 是个“有没有”的检查工具,用来判断子查询有没有返回结果。
  • 如果子查询有哪怕一行结果,EXISTS 就返回 TRUE(真);如果子查询没结果,就返回 FALSE(假)。
  • 通常跟子查询一起用,写成 WHERE EXISTS (子查询)。

union

union语句联合查询,要求列数必须相同,默认去重,如果要保留重复数据,可以使用union all select

INTERSECT 运算符

啥是 INTERSECT?

  • INTERSECT 是个“找交集”的工具,把两个查询的结果比一比,只留下两边都有的行。
  • 就像你有两份名单,一个是篮球队的,一个是足球队的,INTERSECT 能挑出既打篮球又踢足球的人。

咋用?

  • 语法:

    查询1 INTERSECT 查询2;

  • 关键点

    • 两个查询的列数得一样,类型得兼容(跟 UNION 一样)。
    • 自动去重(只留一份重复的)。
EXCEPT运算符

啥是 EXCEPT?

  • EXCEPT 是个“找差集”的工具,把第一个查询的结果拿出来,减去第二个查询的结果,只留下第一个查询独有的行。
  • 就像你有两份名单,一个是全校学生,一个是篮球队的,EXCEPT 能挑出不在篮球队的学生。

联接查询

等值联接

啥意思?

  • 等值联接就是用“等于”(=)来匹配两张表的列,找两边值相等的行。
  • 就像找“学生和班级匹配的记录”,用 class_id 相等来连。
SELECT t.name, c.class_name
FROM test t
JOIN classes c ON t.class_id = c.class_id;

自然联接

啥意思?

  • 自然联接(NATURAL JOIN)是一种特殊的等值联接,自动用两张表里同名列来做等值匹配。
  • 不用写 ON,SQL 自己找同名列(像 class_id)来连,还会把重复的列去掉(结果里只留一份 class_id)。
  • 相当于是自动的等值连接
SELECT t.name, c.class_name
FROM test t
NATURAL JOIN classes c;

非等值连接

就是把=号换成><这样的比较符号

SELECT t.name, c.class_name
FROM test t
JOIN classes c ON t.id > c.min_id;

自身连接

啥意思?

  • 自身联接是自己跟自己连(同一张表),用别名区分两份“自己”。
  • 就像找“同一个班级的学生对”(学生跟学生比)。
SELECT t1.name AS 学生1, t2.name AS 学生2, t1.class_id
FROM test t1
JOIN test t2 ON t1.class_id = t2.class_id
WHERE t1.id < t2.id;

t1 和 t2 是 test 表的两个副本。

t1.class_id = t2.class_id:找同班的。

t1.id < t2.id:避免重复对(比如 enoch-lally 和 lally-enoch 只留一个)。

为啥用?

  • 找表内关系,比如“同班学生”、“员工和他的上级”。

外联接

啥意思?

  • 外联接(OUTER JOIN)保留至少一张表的所有行,匹配不上的填 NULL。
  • 有三种:
    • LEFT OUTER JOIN:左表全留,右表没匹配填 NULL。
    • RIGHT OUTER JOIN:右表全留,左表没匹配填 NULL。
    • FULL OUTER JOIN:两表都留,没匹配填 NULL。

复合条件联接

啥意思?

  • 复合条件联接是用多个条件(用 AND、OR 组合)来匹配两张表。

  • 就像“班级匹配且 ID 大于某个值”。

  • SELECT t.name, c.class_name
    FROM test t
    JOIN classes c ON t.class_id = c.class_id AND t.id > 2;
    

update

update test
set age=3
where name='lally';

delete

delete from test
where name='lally';

索引

唯一索引 (Unique Index)

啥意思?

  • 唯一索引保证索引列(或多列组合)的值不能重复。
  • 就像给学生编号(id),每个人的编号必须唯一,不能有重复。
create unique index my_index on test(name); 

image-20250427220804165

聚集索引(CLUSTERED INDEX)

啥意思?

  • 簇索引(聚集索引)决定表数据的物理存储顺序,有点像按字母顺序排书的书架。
  • 一张表只能有一个簇索引(因为物理顺序只能有一种)。
CREATE CLUSTERED INDEX idx_clustered_class_id ON test(class_id);

通常自动创建:如果你给表加了 PRIMARY KEY,SQL Server 默认会建一个簇索引(除非你指定主键用非簇索引)。

特点

  • 决定数据物理顺序,查询范围(如 WHERE class_id BETWEEN 1 AND 2)超快。
  • 一张表只能有一个簇索引。
  • 插入数据时可能慢(因为要保持顺序,可能会移动数据)。

为啥用?

  • 适合经常按某列排序或范围查询的场景(像 class_id 这种)。
  • 主键默认用簇索引(比如 id)。

非簇索引 (Nonclustered Index)

啥意思?

  • 非簇索引(非聚集索引)是个“独立目录”,不改变数据物理顺序,只存一份“指引”。
  • 就像书后面加了个索引页,告诉你“名字”在哪页,但书本身还是按章节排。非聚集索引将数据在内存中的索引位置记录下来,查找的时候就会很快。
CREATE NONCLUSTERED INDEX idx_nonclustered_name ON test(name);

为啥用?

  • 适合经常查但不排序的列(像 name、phone)。
  • 配合 WHERE、JOIN 加速查询。

存储程序和触发器

存储过程

啥是 Stored Procedure(存储过程)?

简单说

  • 存储过程是一堆预先写好的 SQL 语句,存成一个“程序”,放在数据库里,随时可以调用。
  • 就像你把做蛋糕的步骤(加面粉、打鸡蛋、烤)写成一个食谱,存起来,啥时候想吃蛋糕就直接拿出来用,不用每次都重新写步骤。
CREATE PROCEDURE 存储过程名字
AS
BEGIN-- 你的 SQL 语句
END;

然后用exec或execute调用

用@传入参数

输入输出参数的区别

CREATE PROCEDURE 存储过程名字@参数1 数据类型,         -- 输入参数@参数2 数据类型 OUTPUT   -- 输出参数
AS
BEGIN-- 逻辑
END;

结合返回值和if语句使用存储过程

create procedure find3@findid varchar(10)
as
begindeclare @status int;if not exists (select * from test where id=@findid)beginset @status=0;return @status;end;set @status=1;return @status;
end;declare @sta int;
exec @sta=find3 @findid=1;
if @sta=1print '查到了';
else if @sta=0print '查不到';

调用输出需要需要先声明一个变量存储

DECLARE @Count INT;  -- 声明变量接输出
EXEC CountStudentsByClass @ClassID = 1, @StudentCount = @Count OUTPUT;
PRINT 'Number of students: ' + CAST(@Count AS VARCHAR(10));

修改存储过程可以使用alter

触发器

啥是触发器?

简单说

  • 触发器是一段特殊的存储过程,绑定在表上,当表发生特定操作(比如插入、更新、删除)时自动“触发”运行。
  • 就像你家装了个门铃,有人开门(操作表)时,门铃自动响(触发器跑起来),还能顺手干点事(比如记录谁开了门)。
  • 绑定到特定的表上
CREATE TRIGGER 触发器名字
ON 表名
FOR/AFTER/INSTEAD OF [INSERT, UPDATE, DELETE]
AS
BEGIN-- 你的 SQL 逻辑
END;

触发器的类型

SQL Server 里有三种触发器:

  1. AFTER 触发器

    (也叫 FOR 触发器):

    • 在操作(INSERT、UPDATE、DELETE)完成后再跑。
    • 最常用,比如记录操作日志。
  2. INSTEAD OF 触发器

    • 代替操作执行,操作本身不执行,触发器里的逻辑跑。
    • 比如想阻止删除,改成“假装删”。
  3. DDL 触发器

    (不针对表,针对数据库操作):

    • 响应数据库级操作(像 CREATE TABLE、DROP TABLE),这里不细讲。
create trigger my_tri
on test
after insert,update
as
beginupdate testset remark='kid'where age<3;
end;insert test values(4,'jjj',1,null)
select * from test;

啥是 inserted 和 deleted 表?

简单说

  • inserted 和 deleted 是 SQL Server 在触发器里提供的两个临时虚拟表,用来记录表数据的变化。
  • 它们只在触发器运行时存在,触发器跑完就没了。

作用

  • inserted:存“新数据”(插入或更新后的数据)。
  • deleted:存“旧数据”(删除或更新前的数据)。
  • 就像你改作业,deleted 是改之前的草稿,inserted 是改完的新稿。

关键点

  • 这俩表的结构跟原表(触发器绑定的表)一样。
  • 只在触发器里能用,存储过程或其他地方用不了。

它们在啥时候有数据?

inserted 和 deleted 表的内容取决于触发器的操作类型(INSERT、UPDATE、DELETE):

操作inserted 表deleted 表
INSERT新插入的行
UPDATE更新后的行更新前的行
DELETE被删除的行

数据库设计

数据库设计是啥?

简单说

  • 数据库设计就是规划怎么存数据,设计表结构,确保数据好存、好查、不乱。
  • 就像建房子,先画图纸(概念模型),再按规则砌墙(范式设计),让房子结实又好用。

目标

  • 数据不重复(节省空间)。
  • 查询快(性能好)。
  • 好维护(改数据不出错)。

概念模型设计(基于 E-R 图)

找实体(Entity):

  • 实体是现实世界的东西,比如“学生”、“班级”。
  • 每个实体变成一张表(像 test 表、classes 表)。
  • 实体有属性(比如学生有 id、name、class_id)。

找关系(Relationship):

  • 实体之间的关系,比如“学生属于班级”(一对多)。
  • 关系可能变成外键(class_id 关联 classes 表),或者独立表(多对多关系)。

画 E-R 图

  • 用矩形表示实体(Student、Class)。
  • 用菱形表示关系(BelongsTo)。
  • 用线连接,标明关系类型(1:1、1:N、N:M)。

转成表

  • 实体变成表,属性变成列。
  • 关系用外键或中间表实现。

范式设计(基于规范化理论)

常见范式

  • 第一范式 (1NF)

    :列不可再分,所有值是原子值。

    • 比如不能存 name 列为 “enoch, lally”,得拆成两行。
  • 第二范式 (2NF)

    :非主键列完全依赖主键。

    啥是依赖?

    简单说

    • 依赖(Dependency)是数据库里的一种关系,描述“一个值能不能决定另一个值”。
    • 就像你知道学生的 id,就能查到他的 name,这就是 name 依赖于 id。

    啥叫“不完全依赖”?

    • 如果主键是多列(复合主键),非主键列只依赖主键的一部分,就不满足 2NF。

    • 比如主键是 (student_id, course_id),student_name 只依赖 student_id,这就是“不完全依赖”。

    • 比如 test 表有 id(主键)、name、class_name,class_name 只依赖 class_id(不是主键),不满足 2NF。

    • 解决:拆成两表,test (id, name, class_id) 和 classes (class_id, class_name)。

  • 第三范式 (3NF)

    :非主键列不能传递依赖。

    • 比如 test 表有 id(主键)、class_id、class_name,class_name 依赖 class_id,class_id 依赖 id,不满足 3NF。
    • 解决:把 class_name 放到 classes 表。

啥意思?

  • 第三范式要求:表满足 2NF,并且非主键列之间不能有传递依赖
  • 传递依赖:如果非主键列 A 依赖主键,B 依赖 A,那 B 间接依赖主键,不满足 3NF。

ER相关概念

image-20250428142329817

image-20250428142346614

单值 (Single-Valued) 和 多值 (Multi-Valued)
  • 单值

    :一个实体在关系里最多对应 1 个对方实体。

    • 比如:一个学生只能属于 1 个班级。
  • 多值

    :一个实体在关系里可以对应多个对方实体。

    • 比如:一个班级可以有多个学生。

对方实体 (Other Entity)

啥意思?

  • 对方实体是指关系中“另一边的实体”。

  • 关系是两个实体之间的联系(二元关系),比如

    Student和 Class 的关系

    • 如果你在看 Student,那“对方实体”就是 Class。
    • 如果你在看 Class,那“对方实体”就是 Student。
max-card(E, R)(最大基数)
  • 啥意思

    max-card(E, R)

    表示实体 E 在关系 R 里最多能连几个对方实体。

    • max-card(E, R) = 1:E 是“单值”的,一个 E 最多连 1 个对方。
    • max-card(E, R) = N:E 是“多值”的,一个 E 可以连多个对方。
  • 例子

    • 关系:“学生属于班级”。
      • 一个学生只能属于 1 个班级:max-card(Student, BelongsTo) = 1(单值)。
      • 一个班级可以有多个学生:max-card(Class, BelongsTo) = N(多值)。
min-card(E, R)(最小基数)
  • 啥意思

    min-card(E, R)

    表示实体 E 在关系 R 里最少得连几个对方实体。

    • min-card(E, R) = 1:E 必须至少连 1 个对方实体(强制)。
    • min-card(E, R) = 0:E 可以不连对方实体(可选)。
  • 之前讲过

    max-card(E, R)

    (最大基数),表示最多连几个:

    • max-card 决定单值/多值(1 是单值,N 是多值)。
    • min-card 决定强制/可选(1 是强制,0 是可选)。

二元关系转换

二元关系:两个实体间的关系(Student BelongsTo Class)。

转换规则

  • 一对多:多的一方加外键(Student 加 class_id)。
  • 一对一:任选一方加外键,加 UNIQUE 约束(Person 加 idcard_id)。
  • 多对多:建中间表(StudentCourse 存 student_id 和 course_id)。

强制/可选

  • 强制参与(min-card = 1):外键 NOT NULL。
  • 可选参与(min-card = 0):外键允许 NULL。

弱实体

啥是弱实体?

简单说

  • 弱实体(Weak Entity)是不能独立存在的实体,必须依赖另一个实体(强实体)才能存在。
  • 就像“订单明细”依赖“订单”:没有订单,就不会有订单明细。

比喻

  • 强实体像“人”,可以独立存在(有身份证号)。
  • 弱实体像“人的手”,得依附于人(没有独立身份证号,得靠人来标识)。

关键特点

  • 弱实体没有自己的主键(Primary Key),需要借强实体的主键来一起组成自己的标识。
  • 弱实体和强实体之间的关系通常是“一对多”(强实体是“一”,弱实体是“多”)。

啥是泛化层次结构?

简单说

  • 泛化层次结构(也叫“泛化/特化”或“继承层次”)是 E-R 图里的一种结构,用来表示实体之间的“父子关系”(类似于面向对象里的继承)。
  • 泛化(Generalization):从多个子类型实体抽象出一个父类型实体(从下往上)。
  • 特化(Specialization):把一个父类型实体细分成多个子类型实体(从上往下)。
  • 就像“人”可以分成“学生”和“老师”,“人”是父类型(泛化),而“学生”和“老师”是子类型(特化)。
约束条件
  • 完整约束 (Total Specialization)
    • 父类型的每个实体必须属于某个子类型(不能只有父类型数据)。
    • 双线连接父类型和子类型。
    • 比如:每个 Person 必须是 Student 或 Teacher。
  • 部分约束 (Partial Specialization)
    • 父类型的实体可以不属于任何子类型。
    • 单线连接。
    • 比如:Person 可以只是 Person,不一定是 Student 或 Teacher。
  • 不相交约束 (Disjoint
    • 一个父类型实体只能属于一个子类型(Student 和 Teacher 不重叠)。
    • 用三角形里写 d(disjoint)。
  • 重叠约束 (Overlapping)
    • 一个父类型实体可以属于多个子类型。
    • 用三角形里写 o(overlapping)。
    • 比如:一个 Person 可以既是 Student 又是 Teacher。

函数依赖

先复习:啥是函数依赖?

简单说

  • 函数依赖(Functional Dependency,简称 FD)是描述表里列之间的“决定关系”。
  • 符号:X → Y,意思是如果 X 的值确定,就能唯一决定 Y 的值。
  • 比如:id → name,知道 id 就能确定 name。
Armstrong 公理(三大基本规则)

Armstrong 公理是函数依赖的基础,总是成立。

(1) 自反律 (Reflexivity Rule)
  • 规则:如果 Y 是 X 的子集(Y ⊆ X),那么 X → Y。
  • 通俗解释:如果 Y 包含在 X 里,X 当然能决定 Y,因为 Y 就是 X 的一部分。
  • 例子
    • X = {id, name},Y = {id}。
    • Y 是 X 的子集,所以 id, name → id 成立。
  • 意义:这个规则很简单,主要用来推导“显然”的依赖。
(2) 增补律 (Augmentation Rule)
  • 规则:如果 X → Y,那么对于任意属性集 Z,XZ → YZ(XZ 表示 X ∪ Z)。
  • 通俗解释:如果 X 能决定 Y,那加点无关的属性 Z 进去,X 加 Z 也能决定 Y 加 Z。
  • 例子
    • 已知 id → name。
    • 加个属性 Z = {class_id}。
    • 根据增补律:id, class_id → name, class_id。
  • 意义:可以“扩展”依赖,加入额外的属性。
(3) 传递律 (Transitivity Rule)
  • 规则:如果 X → Y 且 Y → Z,那么 X → Z。
  • 通俗解释:如果 X 能决定 Y,Y 能决定 Z,那 X 也能间接决定 Z。
  • 例子
    • 已知 id → class_id,class_id → class_name(因为 classes 表里有 class_id → class_name)。
    • 根据传递律:id → class_name。
  • 意义:用来发现间接依赖(也是第三范式要消除的传递依赖)。

基于三大公理,可以推导出一些更实用的规则,方便计算依赖。

(1) 并规则 (Union Rule)
  • 规则:如果 X → Y 且 X → Z,那么 X → YZ。
  • 通俗解释:如果 X 能决定 Y,也能决定 Z,那 X 能决定 Y 和 Z 一起。
  • 例子
    • 已知 id → name 和 id → class_id。
    • 根据并规则:id → name, class_id。
  • 推导:可以用增补律和自反律证明。
(2) 分解规则 (Decomposition Rule)
  • 规则:如果 X → YZ,那么 X → Y 且 X → Z。
  • 通俗解释:如果 X 能决定 Y 和 Z 一起,那 X 也能单独决定 Y 和 Z。
  • 例子
    • 已知 id → name, class_id。
    • 根据分解规则:id → name 和 id → class_id。
  • 推导:可以用自反律和传递律证明。
  • 注意:分解规则是并规则的逆向。
(3) 伪传递律 (Pseudo-Transitivity Rule)
  • 规则:如果 X → Y 且 WY → Z,那么 WX → Z。
  • 通俗解释:如果 X 能决定 Y,而 Y 和 W 一起能决定 Z,那 X 和 W 一起也能决定 Z。
  • 例子
    • 已知 id → class_id,class_id, teacher_id → class_name。
    • 根据伪传递律:id, teacher_id → class_name。
  • 推导:可以用增补律和传递律证明。
闭包 (Closure) 的概念
  • 啥是闭包:给定一组函数依赖 F 和属性集 X,X 的闭包 X⁺ 是 X 能决定的所有属性的集合。

  • 咋算闭包:用 Armstrong 公理和推导规则,从 X 开始,逐步推导能决定的属性。

  • 算法

    (简单版):

    1. 初始化:X⁺ = X。
    2. 重复:对于每个依赖 U → V(U 是 X⁺ 的子集),把 V 加到 X⁺。
    3. 直到 X⁺ 不变。
  • 例子

    • 表:test (id, name, class_id)。
    • 函数依赖:F = {id → name, id → class_id}。
    • 求 id的闭包 id⁺
      • 初始:id⁺ = {id}。
      • id → name:加 name,id⁺ = {id, name}。
      • id → class_id:加 class_id,id⁺ = {id, name, class_id}。
      • 结束:id⁺ = {id, name, class_id}。
  • 意义:闭包用来判断 X 能不能决定某个属性,或者是不是候选键。

覆盖和最小覆盖

1. 啥是覆盖 (Cover)?

简单说

  • 覆盖(也叫等价覆盖,Equivalent Cover)是另一组函数依赖 G,它和原来的函数依赖集 F 等价,也就是说,F 和 G 能推导出的所有依赖(闭包)是一样的。
  • 符号:F⁺ = G⁺,表示 F 和 G 的闭包相同。

通俗解释

  • 就像你有两份“说明书”(F 和 G),内容不同,但能干的事(推导的依赖)完全一样。
  • 覆盖的目标是找到一个更“简洁”的函数依赖集,但效果不变。

例子

  • 已知 F = {id → name, id → class_id, class_id → class_name}。
  • 用传递律:id → class_id,class_id → class_name,推出 id → class_name。
  • 构造一个新依赖集 G = {id → name, id → class_id, id → class_name}。
  • 检查:F⁺ 和 G⁺ 都包含 {id → name, id → class_id, id → class_name},所以 G 是 F 的一个覆盖。

意义

  • 覆盖可以用来验证两个依赖集是否等价,或者简化依赖集。

2. 啥是最小覆盖 (Minimal Cover)?

简单说

  • 最小覆盖(Minimal Cover,也叫 Canonical Cover,记作 Fc)是函数依赖集 F

    的一个“最简”覆盖,满足以下条件:

    1. 等价:Fc 和 F 的闭包相同(Fc⁺ = F⁺)。
    2. 每个依赖的右边(Y)只有一个属性(单属性依赖)。
    3. 没有冗余依赖(去掉任何一个依赖都不等价)。
    4. 没有冗余属性(每个依赖的左边和右边都不能再简化)。

通俗解释

  • 最小覆盖就像把说明书“精简”到最短:去掉多余的废话,每句话都很关键,但功能和原来一样。
  • 目标是让函数依赖集尽可能简单,方便规范化设计(比如计算范式)。

求最小覆盖的步骤

给定函数依赖集 F,求最小覆盖 Fc 的步骤如下:

步骤 1:分解右边(单属性化)
  • 把每个依赖的右边拆成单一属性(用分解规则:X → YZ 拆成 X → Y 和 X → Z)。
  • 例子:
    • F = {id → name, class_id; class_id → class_name}。
    • 拆分:id → name, class_id 变成 id → name 和 id → class_id。
    • 新 F = {id → name, id → class_id, class_id → class_name}。
步骤 2:去掉冗余属性(简化左边)
  • 检查每个依赖的左边,看看能不能去掉某些属性。

    • 对于每个依赖 X → Y,检查 X 里的每个属性 A,如果去掉 A 后(X - {A})依然能决定 Y(用闭包计算),就把 A 去掉。
  • 例子:

    • 假设有 F = {id, class_id → name, id → class_id, class_id → class_name}。

    • 检查

      id, class_id → name:

      • 去掉 class_id,用 {id} 算闭包:id⁺ = {id, class_id, name}(包含 name),所以 class_id 冗余。
      • 简化成 id → name。
    • 新 F = {id → name, id → class_id, class_id → class_name}。

步骤 3:去掉冗余依赖
  • 检查每个依赖,看看去掉后是否还等价。

    • 对于每个依赖 X → Y,去掉它,计算剩余依赖的闭包,看 X⁺ 里是否还有 Y。
  • 例子

    • 当前 F = {id → name, id → class_id, class_id → class_name}。

    • 去掉

      id → class_id,剩余

      {id → name, class_id → class_name}

      • 算 id⁺:只有 {id, name},不包含 class_id,说明 id → class_id 不能去。
    • 去掉

      class_id → class_name,剩余

      {id → name, id → class_id}

      • 算 class_id⁺:只有 {class_id},不包含 class_name,说明 class_id → class_name 不能去。
    • 没有冗余依赖,Fc = {id → name, id → class_id, class_id → class_name}。

最终最小覆盖:
  • Fc = {id → name, id → class_id, class_id → class_name}。

再来个复杂点的例子

:R(A, B, C, D)。 函数依赖:F = {A → BC, B → C, A → D}。

求最小覆盖

  1. 分解右边:
    • A → BC 拆成 A → B 和 A → C。
    • B → C(已单属性)。
    • A → D(已单属性)。
    • 新 F = {A → B, A → C, B → C, A → D}。
  2. 去掉冗余属性:
    • A → B:A 不可简化。
    • A → C:A 不可简化。
    • B → C:B 不可简化。
    • A → D:A 不可简化。
    • 没有冗余属性。
  3. 去掉冗余依赖:
    • 去掉 A → C,剩余 {A → B, B → C, A → D}:
      • 算 A⁺:A → B,B → C,所以 A⁺ = {A, B, C, D},包含 C,A → C 冗余。
    • 新 F = {A → B, B → C, A → D}。
    • 再检查:
      • 去掉 A → B,剩余 {B → C, A → D},A⁺ = {A, D},不包含 B,不能去。
      • 去掉 B → C,剩余 {A → B, A → D},B⁺ = {B},不包含 C,不能去。
      • 去掉 A → D,剩余 {A → B, B → C},A⁺ = {A, B, C},不包含 D,不能去。
    • 没有更多冗余依赖。
  4. 最小覆盖:
    • Fc = {A → B, B → C, A → D}。

求闭包的例子

image-20250428191326842

关系模式的分解

简单说

  • 关系模式分解是把一个大表(关系模式)拆成多个小表的过程,目的是满足更高的范式(比如 3NF、BCNF),减少数据冗余和异常。
  • 就像把一个大杂物间整理成几个小柜子,东西放得更有序,找起来也方便。

目标

  • 消除冗余(比如重复数据)。
  • 避免更新异常(插入、删除、更新时不一致)。
  • 保持数据的完整性(不能丢数据,不能改逻辑)。

关系模式分解的两个关键性质

分解时要保证两个性质,否则可能会丢数据或改逻辑。

1. 无损连接 (Lossless Join)
  • 啥意思:分解后,通过连接(JOIN)能完全恢复原表的数据,不丢数据。

  • 咋判断

    :用函数依赖检查:

    • 给定关系模式 R,分解成 R1 和 R2。
    • 如果 R1 ∩ R2 → R1 或 R1 ∩ R2 → R2 成立(基于函数依赖),就是无损连接。
  • 例子

    • 原表 R(id, name, class_id, class_name)。
    • 函数依赖:F = {id → name, class_id; class_id → class_name}。
    • 分解:
      • R1(id, class_id, class_name)。
      • R2(id, name, class_id)。
    • 交集:R1 ∩ R2 = {id, class_id}。
    • 检查:id, class_id → class_name(成立),所以 id, class_id → R1,是无损连接。
2. 依赖保持 (Dependency Preservation)
  • 啥意思:分解后,原来的函数依赖还能通过新表的依赖推导出来(不丢失约束)。
  • 咋判断:
    • 给定函数依赖集 F,分解成 R1 和 R2,分别算 F 在 R1 和 R2 上的投影(只包含 R1 和 R2 属性的依赖)。
    • 如果这些投影能覆盖 F,就是依赖保持。
  • 例子:
    • 原依赖:F = {id → name, class_id; class_id → class_name}。
    • 分解:
      • R1(id, class_id, class_name):投影得 id → class_id, class_id → class_name。
      • R2(id, name, class_id):投影得 id → name, class_id。
    • 合并投影:{id → name, class_id; class_id → class_name},覆盖了 F,依赖保持。

完整性约束,视图,安全,系统目录

完整性约束 (Integrity Constraints)
  • 啥意思:保证数据“正确”和“一致”的规则,约束是完整性约束的一部分。

  • 种类:

    • 实体完整性:主键不能重复且不能为 NULL(比如 id)。
    • 参照完整性:外键值必须存在(比如 class_id 必须在 classes 表里)。
    • 用户定义完整性:业务规则,比如 CHECK (class_id > 0)。
  • 例子:class_id 不能为 NULL(如果强制参与),且必须在 classes 表里有对应值。

  • 约束(Constraint)是数据库里的一套规则,用来限制表里的数据,确保数据的正确性一致性

  • 就像学校的规章制度,约束让数据“守规矩”,避免乱七八糟的情况。

常见约束类型

  • 主键约束 (PRIMARY KEY):确保每行唯一且不为空(比如 id)。
  • 唯一约束 (UNIQUE):列值不能重复(但可以为空)。
  • 非空约束 (NOT NULL):列不能为 NULL。
  • 外键约束 (FOREIGN KEY / REFERENCE):保证引用值存在。
  • 检查约束 (CHECK):限制值的范围或条件。
  • 默认约束 (DEFAULT):给列设置默认值。
CREATE TABLE 表名 (列名 数据类型 CHECK (条件),...
);
或单独加
ALTER TABLE test
ADD CONSTRAINT chk_name_length CHECK (LEN(name) > 2);

外键约束语法

CREATE TABLE 表名 (列名 数据类型,CONSTRAINT 约束名 FOREIGN KEY (列名) REFERENCES 另一表(列名),...
);
discnt real constraint discnt_max check (discnt<=15.0)

discnt的类型是(real),加一个check限制discnt

视图 (Views)
  • 啥意思:视图是一个“虚拟表”,基于实际表(物理表)的查询结果,简化数据访问。
  • 作用:
    • 隐藏复杂查询:用户只看到需要的部分。
    • 保护数据:限制用户访问某些列。
CREATE VIEW student_class_view AS
SELECT t.name, c.class_name
FROM test t
JOIN classes c ON t.class_id = c.class_id;
SELECT * FROM student_class_view;
安全 (Security)
  • 啥意思:控制谁能访问或修改数据库里的数据,保护敏感信息。

  • 方法:

    • 用户权限:用 GRANT和 REVOKE

      分配权限。

      • 比如只允许某用户读 test表:

        GRANT SELECT ON test TO user1;

      • 禁止更新:

        REVOKE UPDATE ON test FROM user1;

    • 角色:给一组用户分配角色,比如 db_reader角色。

      CREATE ROLE db_reader; GRANT SELECT ON test TO db_reader;

    • 视图保护:用视图限制可见数据(比如上面的 student_class_view 只暴露 name 和 class_name)。

  • 例子:

    • 假设 class_name是敏感数据,只允许管理员看:

      GRANT SELECT ON classes TO admin; DENY SELECT ON classes TO public;

数据库安全的四个等级

1. 系统级安全 (System-Level Security)
  • 啥意思:

    • 系统级安全是最外层的防护,关注数据库运行的整个系统环境(操作系统、网络等)。
    • 目的是防止未经授权的用户进入数据库所在的系统。
  • 咋做:

    • 操作系统权限

      :限制谁能登录数据库服务器。

      • 比如:只有 DBA(数据库管理员)能登录服务器,其他人不能。
    • 网络安全

      :保护数据库的网络访问。

      • 用防火墙限制访问(比如只允许特定 IP 访问 SQL Server 的 1433 端口)。
      • 用 SSL/TLS 加密网络传输,防止数据被拦截。
    • 身份验证

      :验证用户身份。

      • SQL Server 支持两种身份验证:
        • Windows 身份验证:用 Windows 用户登录(更安全)。
        • SQL Server 身份验证:用用户名和密码(比如 sa 用户)。
2. 数据库级安全 (Database-Level Security)
  • 啥意思:
    • 数据库级安全关注整个数据库的访问控制,确保只有合法用户能访问数据库。
  • 咋做:
    • 用户管理:创建数据库用户,分配权限。
3. 对象级安全 (Object-Level Security)
  • 啥意思:

    • 对象级安全关注数据库里的具体对象(表、视图、存储过程等),控制用户对这些对象的操作。
  • 咋做:

    • 权限分配:用 GRANT和 REVOKE控制权限。

      • 比如只允许 user1 读 test 表:

        GRANT SELECT ON test TO user1;
        
        DENY UPDATE ON classes TO user1;
        
  1. 数据级安全 (Data-Level Security)

限制用户只能访问某些行和对某些列进行加密等操作,一定程度上保护数据安全

系统目录 (System Catalogs)
  • 啥意思:系统目录是一组特殊的表,存储数据库的“元数据”(Metadata),也就是数据库里所有对象(表、视图、约束等)的描述信息。
  • 作用:
    • DBA 可以查系统目录,了解数据库结构。
    • 比如:有哪些表、表的列、约束、权限等。
  • 在 SQL Server 中:
    • 系统目录包括 sys.tables、sys.columns、sys.foreign_keys 等。

练习题

文件系统和DBMS的四个主要区别

方面文件系统DBMS
数据组织文件分散,无结构化关系表结构,有关系(外键等)
一致性完整性无约束,易不一致有约束、事务,保证一致性
访问查询手写代码,效率低SQL 查询,高效有优化
并发安全无并发控制,安全粗糙并发控制强,细粒度安全

解释物理独立性,以及它在数据库系统中的重要性。

物理独立性是指应用程序和用户查询(逻辑层)不受数据库底层物理存储结构(物理层)变化的影响。

也就是说,数据库的存储方式(比如文件、索引、磁盘分布)变了,应用程序和 SQL 查询不用改,照样能正常工作。

数据库系统通常分三层(ANSI-SPARC 架构):

  1. 外部层(External Level):用户看到的数据视图(比如视图)。
  2. 逻辑层(Conceptual/Logical Level):表的逻辑结构(比如 test 表的列和关系)。
  3. 物理层(Physical Level):底层存储(文件、索引、分区)。

物理独立性是逻辑层和物理层之间的隔离。

其实就是逻辑层(用户查询,表结构)不受物理层(存储,索引)的变化迎新

重要性

  1. 灵活性:随便更改物理存储位置,用户不受影响
  2. 省成本:应用不用改
  3. 性能好:支持底层优化
  4. 可扩展:数据量大也可以轻松调整

找出候选键

ABCDE
a1b1c1d1e4
a1b1c2d2e3
a1b2c3d1e1
a1b2c4d2e2

候选键都是有潜力成为主键的,必须要最简洁,可以用一列就绝对不用两列

相关文章:

  • MySQL 中的最左前缀法则
  • ISO和 IEC机构的区别
  • 信雅达 AI + 悦数 Graph RAG | 大模型知识管理平台在金融行业的实践
  • Microsoft .NET Framework 3.5 离线安装包 下载
  • 【动手学大模型开发】使用 LLM API:智谱 GLM
  • Python中的defaultdict方法
  • 信息过载(Information Overload):太多的信息导致了信息处理能力的饱和
  • JVM | CMS垃圾收集器详解
  • 基于tabula对pdf中的excel进行识别并转换成word(三)
  • FlexNoC-Latency
  • 进程自动守护,监控并自动重启
  • 完整的 SSL 证书生成与 Spring Boot 配置流程
  • MySQL下载与安装
  • 无人设备遥控器之移动手持定位系统篇
  • qtfaststart使用教程(moov置前)
  • MLOps全链路能力:模型监控、版本回滚与持续训练
  • 2025年- H13-Lc120-189.轮转数组(普通数组)---java版
  • MinIO中mc工具的安装、配置、简单使用
  • AI驱动软件工程:SoftEngine 方法论与 Lynx 平台实践分析
  • AI防摔倒检测系统
  • TCL科技一季度净利增超三倍,去年半导体显示业务营收创新高
  • 80后共青团云南省委副书记许思思已任迪庆州委副书记
  • 160名老人报旅行团被扔服务区?张家界官方通报
  • 以“最美通缉犯”为噱头直播?光明网:违法犯罪不应成网红跳板
  • 习近平在上海考察时强调,加快建成具有全球影响力的科技创新高地
  • 美航母一战机坠海,美媒:为躲避胡塞武装攻击,损失超六千万美元