跳转至

5-1. SQL

第一部分:SQL的起源与设计哲学

  • 理论基础:SQL基于关系代数和关系演算,目标是让数据库访问变得简单直观。
  • 声明式语言:用户只需描述"想要什么",而不需要指定"如何获取"。这与网状/层次模型的"过程式"导航形成鲜明对比。
  • 历史发展
  • SEQUEL:IBM在1970年代开发的早期版本。
  • SQL:标准化后成为"Structured Query Language"。
  • 标准化:经过ANSI、ISO等组织标准化,形成了我们今天使用的SQL。

第二部分:SQL语言概览

类别 全称 主要命令 作用
DDL 数据定义语言 CREATE, ALTER, DROP, TRUNCATE 定义和修改数据库结构
DML 数据操作语言 INSERT, UPDATE, DELETE, MERGE 操作数据库中的实际数据
DQL 数据查询语言 SELECT (带有各种子句) 查询和检索数据
DCL 数据控制语言 GRANT, REVOKE 控制访问权限
TCL 事务控制语言 COMMIT, ROLLBACK, SAVEPOINT 管理事务

第三部分:DDL深度解析

CREATE TABLE与约束

CREATE TABLE Students (
    sno VARCHAR(10) PRIMARY KEY,          -- 主键约束
    sname VARCHAR(50) NOT NULL,           -- 非空约束
    gender CHAR(1) CHECK (gender IN ('M', 'F')), -- 检查约束
    dorm_no VARCHAR(5),
    room_no VARCHAR(4),
    -- 复合主键
    PRIMARY KEY (dorm_no, room_no),
    -- 外键约束
    FOREIGN KEY (dorm_no, room_no) REFERENCES Rooms(dorm_no, room_no)
);

约束类型详解: - PRIMARY KEY:主键,唯一标识 + 非空 - UNIQUE:唯一约束,允许NULL值 - NOT NULL:非空约束
- CHECK:检查条件约束 - FOREIGN KEY:外键约束,维护引用完整性

第四部分:DML与DQL精讲

单表查询的完整结构

SELECT [DISTINCT] 属性列表 
FROM 表名
WHERE 条件
GROUP BY 分组属性
HAVING 分组条件
ORDER BY 排序属性;

执行顺序(重要!): FROMWHEREGROUP BYHAVINGSELECTORDER BY

多表查询的三种方式

  1. 显式连接(推荐)

    SELECT s.sname, r.dorm_no
    FROM Students s 
    INNER JOIN Rooms r ON s.dorm_no = r.dorm_no AND s.room_no = r.room_no;
    
  2. 自然连接

    SELECT sname, dorm_no 
    FROM Students NATURAL JOIN Rooms;
    
  3. 隐式连接(传统方式)

    SELECT s.sname, r.dorm_no
    FROM Students s, Rooms r
    WHERE s.dorm_no = r.dorm_no AND s.room_no = r.room_no;
    

聚集查询与分组

基础聚集函数: - COUNT(*) - 统计行数 - COUNT(属性) - 统计非空值 - AVG(), SUM(), MAX(), MIN()

分组查询的要点: - GROUP BY 后面的属性必须出现在 SELECT 中(或者是聚集函数的参数) - WHERE 在分组前过滤,HAVING 在分组后过滤

示例:查询每个宿舍的学生人数(只显示超过5人的宿舍)

SELECT dorm_no, COUNT(*) as student_count
FROM Students 
WHERE gender = 'M'  -- 分组前过滤:只考虑男生
GROUP BY dorm_no 
HAVING COUNT(*) > 5;  -- 分组后过滤:只显示人数>5的宿舍

第五部分:深刻问题解答

问题1:关系数据库Primary Key vs 文档数据库ID机制

特性 关系数据库Primary Key 文档数据库ID
定义方式 用户显式定义,有业务含义 系统自动生成,通常无业务含义
组成 可以是单个属性或复合属性 通常是单个ID字段
业务语义 具有业务意义(学号、身份证号等) 通常无业务意义,纯技术标识
稳定性 相对稳定,变更影响大 稳定不变
查询模式 可通过业务属性直接查询 通常需要通过ID查询

优缺点分析: - Primary Key优点:有业务含义,支持基于业务属性的直接访问,数据关系清晰 - Primary Key缺点:设计复杂,变更困难,可能存在业务属性不稳定问题 - ID机制优点:简单统一,性能优化容易,稳定性好 - ID机制缺点:缺乏业务含义,查询模式受限

现代实践:很多关系数据库同时支持自增ID(代理键)和业务主键,结合两者优点。

问题2:预定义模式 vs 无模式的原因

根本原因:数据模型和设计哲学的不同

方面 关系数据库 文档数据库
理论基础 关系代数,强调结构一致性 面向文档,强调灵活性
设计目标 数据一致性、完整性、减少冗余 开发敏捷性、处理异构数据
数据特征 结构化数据,模式相对稳定 半结构化数据,模式频繁变化
约束维护 数据库级别强制约束 应用级别处理约束
使用场景 事务处理、复杂查询、关键业务数据 内容管理、日志数据、快速原型开发

背后的权衡: - 严格模式 换来了 数据质量保证查询优化能力 - 灵活模式 换来了 开发速度适应变化的能力

问题3:数据库如何检测重复插入

技术实现:索引机制

  1. 创建唯一索引
  2. 当定义PRIMARY KEYUNIQUE约束时,数据库自动在后台创建唯一索引
  3. 这个索引通常使用B+树等数据结构实现

  4. 插入时的检测过程

    开始插入新记录
    提取主键/唯一键的值
    在唯一索引中进行查找
    if (在索引中找到相同键值) then
        抛出唯一约束违反错误
    else
        执行插入操作,同时更新索引
    end if
    
  5. 性能优化

  6. 索引使得查找操作的时间复杂度为O(log n),而不是O(n)
  7. 即使表中有上亿条记录,也能快速完成重复性检查

  8. 事务考虑

  9. 在事务中,数据库还需要检查其他未提交的事务是否插入了相同键值
  10. 这通过锁机制或多版本并发控制(MVCC)来实现

示例:如果你在sno上定义了主键,当插入('1001', '张三')时,数据库会在sno的B+树索引中查找1001,如果找到就拒绝插入。