## QA 1：自然连接与等值连接的区别

**Q**：在关系数据模型中，有一句这样的话："自然连接要求相等的分量必须具有共同的属性，等值连接则不要求"这是什么意思？

**A**：

- **自然连接**：自动寻找两个表中**列名相同**的属性进行匹配连接，结果中相同名称的属性列只出现一次
    
- **等值连接**：可以手动指定**任意列**进行等值匹配，不要求列名相同，结果中用于比较的两列都会保留
    

---

## QA 2：举例说明自然连接与等值连接

**Q**：还是举个例子吧

**A**：  
以学生表(Student)和院系表(Department)为例：

**自然连接** `Student ⋈ Department`：

- 自动基于同名列 Dno 连接
    
- 结果中 Dno 只出现一次
    

**等值连接** `Student ⋈[Student.Dno = Department.Dno] Department`：

- 效果与自然连接相同，但 Dno 会出现两次
    
- 也可以写成 `Student.Sno = Department.Dno`（虽然无意义，但语法允许）
    

**关键区别**：自然连接必须要求两个表有同名的列；等值连接可以指定任意列，不要求列名相同。

---

## QA 3：两段 SQLite 相关子查询的含义

**Q**：上述两段 SQLite 语句，是相关子查询，分别是什么意思？

**A**：

**第一个查询**（查找没有分配任何项目的员工）：

sql

SELECT * FROM Employee
WHERE NOT EXISTS
    (SELECT * FROM Item_Emp WHERE Item_Emp.Eno = Employee.Eno)

- 查找在 Item_Emp 表中没有对应记录的员工
    
- 即没有参加任何项目的员工
    

**第二个查询**（查找负责所有项目的员工）：

sql

SELECT Eno, Ename FROM Employee 
WHERE NOT EXISTS 
    (SELECT * FROM Item 
     WHERE NOT EXISTS
        (SELECT * FROM Item_Emp
         WHERE Item_Emp.Eno = Employee.Eno
         AND Item_Emp.Ino = Item.Ino))

- 双重嵌套相关子查询
    
- 查找负责了所有项目的员工（除法操作）
    
- 即不存在任何一个项目是该员工不负责的
    

---

## QA 4：每一步 WHERE 的具体含义

**Q**：每一步的 where 到底什么意思？能够分析一下吗

**A**：

**第一个查询**：

- 外层 `WHERE NOT EXISTS`：对每个员工检查是否不存在匹配记录
    
- 子查询 `Item_Emp.Eno = Employee.Eno`：查找该员工的项目记录
    
- 组合逻辑：找不到匹配 → 该员工没有项目 → 被选中
    

**第二个查询**：

- 最外层 `NOT EXISTS`：检查是否不存在"该员工缺失的项目"
    
- 中层 `SELECT * FROM Item WHERE NOT EXISTS`：查找是否存在该员工没负责的项目
    
- 最内层：检查该员工是否负责当前项目
    
- 组合逻辑：如果找不到任何"不负责的项目" → 该员工负责所有项目
    

**关键理解**：嵌套的 NOT EXISTS 会反转逻辑，双重否定相当于"全部满足"。

---

## QA 5：哪里体现了"全部项目"？

**Q**：哪里体现了"全部项目"？WHERE Item_Emp.Eno = Employee.Eno AND Item_Emp.Ino = Item.Ino 这一段吗？

**A**：  
是的，这段是关键，但需要结合双重 NOT EXISTS 理解：

- `Item_Emp.Eno = Employee.Eno AND Item_Emp.Ino = Item.Ino` 建立了员工与项目的负责关系
    
- **双重否定表全部**：外层 NOT EXISTS + 内层 NOT EXISTS = "不存在不满足的情况" = "全部满足"
    
- 逻辑等价：¬∃item ∈ Item, ¬∃assignment(负责) ≡ ∀item ∈ Item, ∃assignment(负责)
    
- 即"对于所有项目，都存在该员工的负责记录" → 负责全部项目
    

---

## QA 6：WHERE NOT EXISTS 为真时返回什么？

**Q**：但它是 where not exists 啊？where 子句为真的时候返回的是没有参加项目的职工信息吗？

**A**：  
你的理解需要区分两个查询：

**第一个查询**：✅ 你的理解正确

- `WHERE NOT EXISTS` 为真 → 返回**没有参加任何项目**的职工
    

**第二个查询**：❌ 不是返回没有参加项目的职工

- 双重 NOT EXISTS 返回的是**参加了所有项目**的职工
    
- 原因：双重否定 = 全部满足
    

**逻辑等价转换**：

sql

-- 第二个查询等价于：
WHERE NOT EXISTS (
    SELECT * FROM Item 
    WHERE Item.Ino NOT IN (
        SELECT Ino FROM Item_Emp WHERE Eno = Employee.Eno
    )
)

**记忆技巧**：

- 单层 NOT EXISTS：检查"完全没有"
    
- 双重 NOT EXISTS：检查"完全没有不满足的情况" = "全部满足"
    

---

## QA 7：内层 WHERE NOT EXISTS 的理解

**Q**：第二个语句中的内层 WHERE NOT EXISTS (...) 它是 where not exists 啊？where 子句为真的时候返回的是这个职工没有参加的项目。会导致外层的 where not exists 为假（只有当为空时才为真，即负责了所有的项目会导致内层 where not exists 返回的为空）。这样理解对吗？

**A**：  
✅ **你的理解完全正确！**

**逻辑分解**：

1. **最内层 NOT EXISTS**：
    
    - 为真 → 该员工**没有**负责当前检查的项目
        
    - 为假 → 该员工**已经**负责当前项目
        
2. **中层 WHERE NOT EXISTS**：
    
    - 当内层对某个项目返回真（员工没负责），中层找到记录 → 中层 NOT EXISTS 为假
        
    - 只有当对所有项目内层都返回假（员工都负责了），中层结果为空 → 中层 NOT EXISTS 为真
        
3. **最外层效果**：
    
    - 中层为真 → 该员工负责了所有项目
        
    - 中层为假 → 该员工至少有一个项目没负责
        

**你的结论完全准确**：

> "返回的是没有 没有参加所有项目的员工"  
> 即：返回的是**不存在未参加项目**的员工 = **参加了所有项目**的员工

---

## QA 8：SELECT * 在查询与视图中的区别

**Q**：查找语句用 SELECT 语句获得查找表，与建立视图的时候也要 SELECT 语句建立视图表，这二者究竟有什么区别？

**A**：

|特性|普通查询|视图|
|---|---|---|
|**本质**|即时执行，返回临时结果集|存储查询定义，是虚拟表|
|**持久性**|结果不存储|定义永久存储在系统表|
|**执行时机**|执行时立即运行|被引用时才执行|
|**数据时效**|执行时刻的快照|每次访问都是最新数据|
|**列结构**|新执行会反映最新结构|多数 DBMS 创建时锁定列结构|
|**性能影响**|单次执行|每次访问都有效率影响|
|**安全控制**|基于底层表|可单独设置权限|

**最佳实践**：

- 避免在视图中使用 `SELECT *`，明确列出列名
    
- 普通查询中也应明确指定所需列
    
- 对频繁使用的复杂查询考虑使用视图
    

---

## QA 9：关于"固定不变"的疑问

**Q**：更新影响：结果集固定不变，随基础表数据变化自动更新。怎么可能固定不变呢？比如说新增一列的话，肯定都会变啊？

**A**：  
您提出了很好的观察点！需要更精确地解释：

**普通查询结果集的"固定性"**：

- **数据内容固定**：执行时刻的数据快照，后续变化不影响已获得的结果集
    
- **列结构固定**：已执行的查询结果不会自动包含新列；但**新执行的查询**会包含新列
    

**视图的"动态性"**：

- **数据内容动态**：每次查询都重新执行，自动反映最新数据
    
- **列结构动态**（取决于 DBMS）：
    
    - 多数数据库（MySQL、PostgreSQL）：创建时 `SELECT *` 锁定当时列，新增列需 `ALTER VIEW`
        
    - 少数数据库（SQL Server 某些配置）：可能动态包含新列
        

**实际例子**：

sql

-- 10:00 创建视图
CREATE VIEW emp_view AS SELECT * FROM employees;
-- 10:05 新增列和数据
ALTER TABLE employees ADD phone VARCHAR(20);
INSERT INTO employees VALUES (4, '李四', 8000, '13800138000');
-- 10:10 查询对比
SELECT * FROM @result;       -- 只有 3 列，无李四记录（固定不变）
SELECT * FROM emp_view;      -- 仍为 3 列（多数 DBMS），但有李四记录
SELECT * FROM employees;     -- 4 列，包含所有数据

**关键点**：

- "固定不变"指的是**已获得的结果集**不会自动更新
    
- 视图的"自动更新"指的是**数据内容**，列结构多数 DBMS 需要手动刷新
    
- 避免依赖 `SELECT *`，明确列出列名更安全
    

---

## 核心知识点汇总

1. **自然连接 vs 等值连接**：自然连接自动基于同名列，等值连接可指定任意列
    
2. **双重 NOT EXISTS**：通过双重否定实现"全部"语义
    
3. **查询结果 vs 视图**：临时快照 vs 动态虚拟表
    
4. **避免 SELECT ***：在视图和查询中都应明确列出列名
    
5. **相关子查询**：外部表的列可在内部查询中使用，实现逐行检查