Skip to content

关系代数-SQL对照表

约 2013 字大约 7 分钟

2025-11-03

  1. 符号像天书πσ… 这些希腊符号对我们来说太陌生了,远没有SQL语句里的 SELECTFROMWHERE 来得直观。
  2. 感觉离实际很远:“我直接写SQL就能查数据,为什么还要学这个?” 这是关系代数是SQL的“底层逻辑”,理解了它,你才能更懂SQL,写出更好的查询。

关系代数与SQL对照全览表

类别关系代数符号读法对应SQL子句比喻功能说明与数学表示
集合运算符R  SR \ ∪ \ S并 (Union)UNION合并清单结果包含所有在RRSS或两者中的元组(去重): {ttR  tS}\{ t \mid t \in R \ ∨ \ t \in S \}
R  SR \ ∩ \ S交 (Intersection)INTERSECT找共同项结果包含所有同时属于RRSS的元组: {ttR  tS}\{ t \mid t \in R \ ∧ \ t \in S \}
R  SR \ - \ S差 (Difference)EXCEPT划掉已有项结果包含所有在RR中但不在SS中的元组: {ttR  tS}\{ t \mid t \in R \ ∧ \ t \notin S \}
R × SR \ × \ S笛卡尔积 (Cartesian Product)CROSS JOIN全能组合结果包含RR中每个元组与SS中每个元组的所有可能组合
专门关系运算符condition(R)\partial_{condition}(R)选择 (Selection)WHERE横向筛选(挑行)从关系RR中选出满足条件conditioncondition的元组: {ttR  condition(t)}\{ t \mid t \in R \ ∧ \ condition(t) \}
πA1,A2,...,Ak(R)\pi_{A_1, A_2, ..., A_k}(R)投影 (Projection)SELECT (指定列时)纵向筛选(选列)从关系RR中提取指定属性列A1,A2,...,AkA_1, A_2, ..., A_k,并去除重复元组
R  SR \ ∞ \ S
R θ SR \ ∞_{\theta} \ S
连接 (Join)
条件连接
JOIN ... ON
NATURAL JOIN
智能拼接自然连接: 在所有同名属性上等值连接
θ-连接: R θS=θ(R × S)R \ ∞_{\theta} S = \partial_{\theta}(R \ × \ S)
R ÷ SR \ ÷ \ S除 (Division)通过 NOT EXISTS 子查询实现查询“全部”解决“对所有...”查询。设R(X,Y)R(X, Y)S(Y)S(Y),则 R ÷ S={tXtSS,(tX,tS)R}R \ ÷ \ S = \{ t_X \mid \forall t_S \in S, (t_X, t_S) \in R \}
逻辑运算符P  QP \ ∧ \ Q与 (And)AND并且逻辑与,连接条件。
P  QP \ ∨ \ Q或 (Or)OR或者逻辑或,连接条件。
¬ P¬ \ P非 (Not)NOT不是逻辑非,取反。

使用您提供符号的严谨表达式示例

例1:查询计算机系男生的姓名

πSn(Sd=CS  Sg=M(Student))\pi_{Sn}(\partial_{Sd='CS' \ ∧ \ Sg='M'}(Student))

对应SQL:

SELECT Sn FROM Student WHERE Sd = 'CS' AND Sg = 'M';

例2:查询选修了课程C1的学生姓名

πSn(C#=C1(SC)  Student)\pi_{Sn}(\partial_{C\#='C1'}(SC) \ ∞ \ Student)

对应SQL:

SELECT S.Sn 
FROM SC JOIN Student S ON SC.S# = S.S# 
WHERE SC.C# = 'C1';

例3:查询选修了全部课程的学生学号

πS#,C#(SC) ÷ πC#(Course)\pi_{S\#, C\#}(SC) \ ÷ \ \pi_{C\#}(Course)

对应SQL:

SELECT DISTINCT S# FROM SC S1
WHERE NOT EXISTS (
    SELECT C# FROM Course
    WHERE NOT EXISTS (
        SELECT * FROM SC S2 
        WHERE S2.S# = S1.S# AND S2.C# = Course.C#
    )
);

Deepseek睡前故事

用人类友好的方式解释一下 "笛卡尔积 选择 投影 链接"

普通人如何“看”表格 vs. 数据库如何“操作”表格

作为一个咖啡馆老板,当你看着Excel里的订单表时,你的大脑是这样工作的:

  • 整体扫描:你的视线会快速扫过整个表格,行列信息同时涌入脑海。你可能会先看标题行,然后顺着某一行读下去,了解一个完整订单的所有信息。
  • 模式识别:你一眼就能看到“张三”这个名字在“顾客名”这一列里出现了好几次。
  • 关联思考:当你在订单表里看到“顾客ID: 101”,你的大脑会本能地联想到:“哦,101就是那个爱坐角落的张先生”。你已经在潜意识里完成了连接操作。

这是一种二维的、并行处理的人类智能。

现在,让我们看看数据库(关系代数)是如何“看”这张表的。它不是一个有智慧的生物,而是一个极其精准但“刻板”的机械臂系统。它永远在“盲操作”。


咖啡馆的“机械臂”分拣系统

想象你的仓库里有一个盲操作的机械臂和一条传送带。表格的每一行(一个订单记录)就是一个放在传送带上的文件袋,袋子上贴着标签(行数据),里面装着这个订单的所有资料(列数据)。

1. 投影:机械臂的“取物夹”

  • 你的指令:“我只想知道所有订单的【顾客名】和【饮品】。”
  • 机械臂操作
    • 机械臂看不到文件袋里有什么。它必须拿起每一个文件袋,打开。
    • 然后,它配备了一个只夹取特定纸张的“取物夹”。这个夹子只会夹出“顾客名”和“饮品”这两张纸。
    • 最后,它把这两张纸放入一个新的、更薄的文件袋,放到另一条传送带上。
    • 关键区别:你作为人,可以一眼锁定“顾客名”这一列。而机械臂必须处理每一行,并纵向地从每一行中剥离出不需要的列。投影是纵向的、针对列的操作,但它必须作用于每一行来实现。

2. 选择:机械臂的“检测器”

  • 你的指令:“把所有【金额大于30元】的订单找出来。”
  • 机械臂操作
    • 传送带经过一个“检测门”,这个门只检测文件袋标签上“金额”这个值。
    • 如果金额>30,检测门亮绿灯,文件袋继续传送到“大额订单”区域。
    • 如果金额<=30,检测门亮红灯,一个推杆会把文件袋推落到“普通订单”筐里。
    • 关键区别:你一眼就能在表格里高亮所有金额大于30的行。而机械臂必须逐行、横向地进行判断和筛选。选择是横向的、针对行的过滤。

3. 连接:机械臂的“配对站”

  • 你的指令:“把订单和下单顾客的电话号码匹配起来。”
  • 机械臂操作
    • 现在有两条传送带:一条是订单文件袋(里面有顾客ID),另一条是顾客文件袋(里面有顾客ID和电话)。
    • 配对站的工作是:拿起一个订单文件袋,读出它的“顾客ID”,比如是“101”。
    • 然后它在顾客文件袋的堆栈里,疯狂地翻找标签上顾客ID也是“101”的那个文件袋。
    • 找到后,它把顾客文件袋里的“电话号码”纸条复印一份,和订单文件袋里的所有纸条装订在一起,形成一个新的、更厚的文件袋。
    • 关键区别:你作为人,可以同时在两张大表上找到“101”这个信息并建立联系。而机械臂是在盲目地、一对一地进行匹配和拼接。它不知道“101”是谁,它只执行规则。

4. 笛卡尔积:机械臂的“暴力复印机”

  • 你的指令:(通常你不会直接下这个指令)“把每个顾客和每种饮品都组合一遍。”
  • 机械臂操作
    • 复印机拿起顾客表的每一个文件袋(张三、李四)。
    • 对于“张三”这个文件袋,它把它分别和饮品单的每一个文件袋(美式、拿铁、奶茶)复印并装订在一起,得到(张三-美式,张三-拿铁,张三-奶茶)三个新文件袋。
    • 然后对“李四”重复上述操作。
    • 关键区别:这会产生大量无意义的组合(比如李四可能从不喝奶茶)。你作为人绝不会这么干,但这是机械臂执行某些复杂任务(如连接)时,可能发生的原始、笨拙的第一步

结论

所以,区别在于:

  • 普通人看表:是二维的、整体的、智能的、关联的。你一眼就能获取行列信息并理解其含义。
  • 数据库操作表:是一维的、序列化的、机械的、盲操作的。它把表格看作一系列独立的行(元组),通过一条简单的指令流(关系代数),对这些行进行纵向裁剪(投影)横向过滤(选择)横向拼接(连接)

未提供算术比较符版本,算术比较符版本人类易读性较高