关系模型 & SQL 基础
第一章:数据库系统概论与数据模型 (Introduction & Data Models)
1. 核心概念解释
- 数据库 (Database) vs. 数据库管理系统 (DBMS)
- 数据库是模拟现实世界的互相关联的数据集合(如:学生名单、音乐专辑列表)。
- DBMS 是管理这些数据的软件系统,负责数据的存储、查询、安全与一致性。
- 为什么不用 CSV 文件管理数据?
- 虽然可以使用文本文件(如 CSV)存储数据,但手动编写代码去解析文件存在巨大缺陷:查询效率低(线性扫描)、难以保证数据一致性(如两个线程同时写入)、缺乏类型安全、原子性无法保证(写到一半断电会导致数据损坏)。
- 数据模型 (Data Model)
- 是描述数据的高层抽象,定义了允许存在的数据类型及其相互关系(类似于建筑蓝图的规则)。
- 关系模型 (Relational Model):当前最主流的数据模型,由 Ted Codd 在 1970 年代提出。它将数据定义为关系 (Relations) 的集合。
2. 关键结论 / 方法
- 早期导航式模型的失败:
- 在关系模型之前(如 CODASYL),程序员必须了解数据的物理存储结构(如链表、树),编写复杂的遍历代码(导航)。如果数据库物理结构改变,所有查询代码都要重写。
- 关系模型的胜利:
- 提供了数据独立性 (Data Independence)。
- 物理数据独立性:用户只需关注逻辑层(Logical Schema),无需关心物理层(Physical Schema)如何存储数据(如文件布局、索引结构)。系统可以在不破坏应用程序的情况下优化物理存储。
3. 易混点或易错点提示
- 误区:认为数据库就是 SQL。
- 纠正:SQL 是语言,DBMS 是系统。市面上有多种 DBMS(Postgres, MySQL, Oracle 等),它们大多遵循关系模型,但实现细节不同。
- 误区:NoSQL 完全取代了 SQL。
- 纠正:虽然 NoSQL(如 Mongo, Redis)曾流行,但关系模型仍是基石。现代 SQL 标准已吸收了 JSON、Graph 等特性。
4. 简短复习小结
DBMS 解决了直接使用文件存储数据带来的完整性与并发问题。关系模型通过将逻辑与物理分离,使程序员能够声明“想要什么数据”而不是“如何找到数据”,这是数据库技术发展的关键转折点。
第二章:关系模型与关系代数 (Relational Model & Algebra)
1. 核心概念解释
- 关系 (Relation):
- 即数学上的“集合”,在数据库中通常表现为表 (Table)。
- 由元组 (Tuple)(即行)和属性 (Attribute)(即列)组成。
- 无序性:在关系模型理论中,关系是无序集合 (Unordered Set),没有重复元素。
- 键 (Keys):
- 主键 (Primary Key):唯一标识元组的属性。
- 外键 (Foreign Key):指向其他关系中主键的属性,用于建立表与表之间的逻辑联系,而非物理指针。
- 关系代数 (Relational Algebra):
- 一种过程化语言 (Procedural Language),定义了查询的执行步骤。它是 SQL 的理论基础,也是数据库引擎内部执行查询的基石。
2. 关键结论 / 公式 / 方法
- 七个基本操作符:
- 选择 (Select, ):根据谓词过滤行(对应 SQL 的
WHERE)。 - 投影 (Projection, ):选择特定的列,并可能重新排序或计算(对应 SQL 的
SELECT列表)。 - 并集 (Union, ):合并两个关系(需结构相同)。
- 交集 (Intersection, ):取两个关系的共有部分。
- 差集 (Difference, ):取存在于第一个关系但不在第二个关系的部分。
- 笛卡尔积 (Product, ):将两个关系的行两两组合。
- 连接 (Join, ):结合笛卡尔积与选择操作,基于相关属性合并两个关系。
- 选择 (Select, ):根据谓词过滤行(对应 SQL 的
3. 易混点或易错点提示
- Set vs. Bag:
- 易错点:严格的关系代数基于集合 (Set)(无重复),但实际的 SQL 语言基于多重集 (Bag)(允许重复)。SQL 需要显式使用
DISTINCT去除重复,因为自动去重代价昂贵。
- 易错点:严格的关系代数基于集合 (Set)(无重复),但实际的 SQL 语言基于多重集 (Bag)(允许重复)。SQL 需要显式使用
- 操作顺序:
- 在关系代数中,操作顺序很重要(例如先过滤再 Join 通常比先 Join 再过滤更高效)。SQL 允许用户不关心顺序,由优化器决定。
4. 简短复习小结
关系模型用表来组织数据,用外键建立联系。关系代数提供了一套操作符(如选择、投影、连接)来处理这些表。理解关系代数有助于理解 SQL 查询在底层是如何被“组装”和执行的。
第三章:SQL 基础与聚合查询 (SQL Basics & Aggregations)
1. 核心概念解释
- SQL (Structured Query Language):
- 一种声明式语言 (Declarative Language)。用户告诉系统“即使要什么结果”(What),由系统决定“如何计算”(How)。
- 包含 DML(数据操作)、DDL(数据定义)、DCL(数据控制)。
- 聚合函数 (Aggregates):
- 将多行数据压缩为单一值的函数,如
AVG,MIN,MAX,SUM,COUNT。
- 将多行数据压缩为单一值的函数,如
2. 关键结论 / 公式 / 方法
- 基本查询结构:
SELECT->FROM->WHERE。 - 分组聚合 (Group By):
- 利用
GROUP BY将数据分桶,然后对每个桶进行聚合计算。
- 利用
- 过滤聚合结果 (Having):
WHERE用于在聚合前过滤原始行。HAVING用于在聚合后过滤结果(例如:找出平均分大于 3.9 的课程)。
3. 易混点或易错点提示
- GROUP BY 的列限制:
- 如果在
SELECT中使用了聚合函数(如AVG(GPA)),那么SELECT列表中出现的其他非聚合列(如CourseID)必须出现在GROUP BY子句中。否则结果是未定义的(虽然 MySQL 早期版本允许,但这是错误的)。
- 如果在
- NULL 的处理:
- 聚合函数通常会忽略 NULL 值,但
COUNT(*)会计算所有行,包括含 NULL 的行。
- 聚合函数通常会忽略 NULL 值,但
4. 简短复习小结
SQL 是通过声明式语法操作关系数据的标准。掌握 GROUP BY 和 HAVING 的区别是进行复杂数据分析的基础。记住:SQL 是基于 Bag(允许重复)的,而关系理论是基于 Set 的。
第四章:高级 SQL 与现实世界的坑 (Advanced SQL & Real-World Implementation)
1. 核心概念解释
- 字符串操作:不同数据库对字符串的大小写敏感度处理不同(Postgres 敏感,MySQL 通常不敏感)。
- 日期与时间:这是 SQL 中最混乱的部分。不同系统获取当前时间的函数不同(
NOW(),CURRENT_TIMESTAMP,GETDATE()等),计算日期间隔的语法也大相径庭。 - 嵌套查询 (Nested Queries):在查询中嵌入另一个查询。
- CTE (Common Table Expressions):使用
WITH语句创建临时结果集,比嵌套查询更具可读性。
2. 关键结论 / 公式 / 方法
- 窗口函数 (Window Functions):
- 允许在不聚合(不减少行数)的情况下进行“滑动窗口”计算(如移动平均、排名)。
- 语法:
FUNC() OVER (PARTITION BY ... ORDER BY ...)。 ROW_NUMBER()vsRANK():用于生成行号或排名。
- Lateral Joins:
- 允许在同一层级中,后续的子查询引用前面表的列(类似于
for loop内部引用外部变量),非常强大但并非所有系统支持。
- 允许在同一层级中,后续的子查询引用前面表的列(类似于
3. 易混点或易错点提示
- 标准与实现的差异:
- 没有任何一个数据库完全严格遵循 SQL-92 或更新的标准。
- 例如:Postgres 的双引号
"用于标识符(表名/列名),单引号'用于字符串常量;而 MySQL 可能混用。 - 重要提示:在很多系统中,计算两个日期的差值(如
2025-01-01减去2024-01-01)可能会导致意想不到的结果(有的返回天数,有的返回莫名其妙的整数),务必查阅具体文档。
4. 简短复习小结
虽然 SQL 是标准,但不同厂商(Postgres, MySQL, SQLite, DuckDB)在细节上有诸多差异,特别是日期处理和字符串操作。在处理复杂逻辑时,推荐使用 CTE 替代深层嵌套子查询以提高代码可读性。
附录:现代数据栈案例 (dbt)
- dbt (data build tool):
- 背景:传统数据仓库中存在大量混乱的脚本、缺乏版本控制、逻辑重复。
- 核心思想:将数据转换逻辑(Transform)视为代码。使用 SQL 编写转换逻辑(
SELECT语句),dbt 负责将其物化为表或视图。 - 价值:带来了软件工程的最佳实践(版本控制、测试、文档、血缘分析)到数据分析领域。
寄语:
“SQL 也许不是最完美的语言,但它是在数据领域生存的必备技能。学会它,并理解不同系统间的细微差别,你将受益终身。”