只需掌握四个查询,就能解决 95% 的 SQL 问题

在数据分析和管理中,掌握复杂查询逻辑是关键技能。即使在人工智能应用中,80%以上的时间都用于数据处理。
所谓 “garbage in, garbage out” 说明了数据质量的重要性。
而写好查询是数据处理的第一步。一个错误的查询可能毁掉整个模型。

今天,我将通过一个有趣的案例,向你展示如何从自然语言到SQL查询的转化。这不仅是一次技术之旅,更是一场逻辑的魔法秀。

关系模式 (Relational Schema)

学生表:Student(Sid, Name, Major, Birthdate)
课程表:Course(Cid, CName, Dept)
课程选修表:Enroll(Sid, Cid, Quarter, Grade)

查询的自然语言描述 (Queries)

Q1: 查找那些选修了Sid 为 928521 的同学选修的课程,并且在相同学期内选修这些课程的学生。

Q2: 查找那些选修了Sid 为 928521 的同学选修的所有课程,并且在相同学期内选修这些课程的学生。

Q3: 查找那些选修了Sid 为 928521 的同学选修的课程,并且在相同学期内选修这些课程的学生。

Q4: 查找那些选修了Sid 为 928521 的同学选修的所有课程,并且在相同学期内选修这些课程的学生。

查询中的逻辑解读

韦恩图:学生 s s s 选修的课程 与 928521 选修的课程 的关系。 U U U 表示所有学生:
image.png

Q1: s s s 的课程要与 928521 的课程有交集。

Q2: 928521 的课程是 s s s 的课程的子集,928521 的任何课程都被 s s s 选修了。

Q3: s s s 的课程是928521 的课程的子集,928521 的任何没有选修的课程, s s s 不可能选修。

Q4: s s s 的课程和 928521 的课程是同一个集合。

解决问题步骤

1.将自然语言查询翻译成一阶逻辑 (First Order Language) 语言表达 (一阶逻辑表达式不包含 全称量词逻辑蕴含);

2.将一阶逻辑语言翻译成关系代数 (Relational Algebra) 语言表达;

3.将关系代数语言翻译成 SQL 查询。

Step1. 自然语言 --> 一阶逻辑

这里我先规定一些变量和谓词:

  • 变量: s s s 来表示某个学生, c c c 表示某个课程, q q q 表示某个学期。
  • 谓词: e n r o l l ( s , c , q ) enroll(s,c,q) enroll(s,c,q) 表达某个学生 s s s 在某个学期 q q q 选修了课程 c c c。为了表达式的简单,我们不单独为学生和课程定义谓词了。

Q1:描述一个学生集合,这些学生要选修 928521 这个同学选修了的课程,并且还是在同一学期选修的:
{ s ∣ ( ∃ c ) ( ∃ q ) [ e n r o l l ( 928251 , c , q ) ∧ e n r o l l ( s , c , q ) ] ∧ s ≠ 928251 } \{s|(\exists c)(\exists q)[enroll(928251,c,q)\land enroll(s,c,q)]\land s\not=928251\} {s(c)(q)[enroll(928251,c,q)enroll(s,c,q)]s=928251}

Q2:根据 s s s 选修了 928521 的所有课程,如果 928521 选修了某门课, s s s 必定也选修了 (因为 s s s 上了 928521 所有的课):
{ s ∣ ( ∀ c ) ( ∀ q ) [ e n r o l l ( 928251 , c , q ) ⇒ e n r o l l ( s , c , q ) ] ∧ s ≠ 928251 } \{s|(\forall c)(\forall q)[enroll(928251,c,q)\Rightarrow enroll(s,c,q)]\land s\not=928251\} {s(c)(q)[enroll(928251,c,q)enroll(s,c,q)]s=928251}
Q3:根据 s s s 选修 928521 的课,如果 s s s 选修了某门课,928521 必定也选修了:
{ s ∣ ( ∀ c ) ( ∀ q ) [ e n r o l l ( s , c , q ) ⇒ e n r o l l ( 928251 , c , q ) ] ∧ s ≠ 928251 } \{s|(\forall c)(\forall q)[enroll(s,c,q)\Rightarrow enroll(928251,c,q)]\land s\not=928251\} {s(c)(q)[enroll(s,c,q)enroll(928251,c,q)]s=928251}
Q4:Q2 和 Q3 条件的并:
{ s ∣ ( ∀ c ) ( ∀ q ) [ e n r o l l ( s , c , q ) ⇔ e n r o l l ( 928251 , c , q ) ] ∧ s ≠ 928251 } \{s|(\forall c)(\forall q)[enroll(s,c,q)\Leftrightarrow enroll(928251,c,q)]\land s\not=928251\} {s(c)(q)[enroll(s,c,q)enroll(928251,c,q)]s=928251}
⇔ \Leftrightarrow 表示逻辑等价 (也可以用 ≡ \equiv 表示): q ⇒ p ∧ p ⇒ q ≡ q ⇔ q q\Rightarrow p\land p\Rightarrow q \equiv q\Leftrightarrow q qppqqq

Step2. 一阶逻辑 --> 关系代数

学生表:Student(Sid, Name, Major, Birthdate)
课程表:Course(Cid, CName, Dept)
课程选修表:Enroll(Sid, Cid, Quarter, Grade)

Q1: { s ∣ ( ∃ c ) ( ∃ q ) [ e n r o l l ( 928251 , c , q ) ∧ e n r o l l ( s , c , q ) ] ∧ s ≠ 928251 } \{s|(\exists c)(\exists q)[enroll(928251,c,q)\land enroll(s,c,q)]\land s\not=928251\} {s(c)(q)[enroll(928251,c,q)enroll(s,c,q)]s=928251} 这个一阶逻辑简化了关系代数的每个部分,我们可以把原查询拆分为多个关系代数表达式:

  • T 11 : = π C i d , Q u a r t e r ( σ S i d = 928251 ( E n r o l l ) ) ) T_{11}:=\pi_{Cid,Quarter}(\sigma_{Sid=928251}(Enroll))) T11:=πCid,Quarter(σSid=928251(Enroll))) 对应一阶逻辑表达式 e n r o l l ( 928251 , c , q ) enroll(928251,c,q) enroll(928251,c,q) 。其中 π \pi π 表示选择哪些列, σ \sigma σ 表示关系选择条件。
  • T 12 = π S i d , C i d , Q u a r t e r ( E n r o l l ) T_{12}=\pi_{Sid,Cid,Quarter}(Enroll) T12=πSid,Cid,Quarter(Enroll) 对应一阶逻辑表达式 e n r o l l ( s , c , q ) enroll(s,c,q) enroll(s,c,q)
  • T 13 = σ S i d ≠ 928521 ( T 12 ) T_{13}=\sigma_{Sid\not= 928521}(T_{12}) T13=σSid=928521(T12) 对应一阶逻辑表达式 e n r o l l ( s , c , q ) ∧ s ≠ 928521 enroll(s,c,q)\land s\not=928521 enroll(s,c,q)s=928521
  • T 14 = T 11 ∧ T 13 T_{14}=T_{11}\land T_{13} T14=T11T13 对应一阶逻辑表达式 e n r o l l ( 928251 , c , q ) ∧ e n r o l l ( s , c , q ) ] ∧ s ≠ 928251 enroll(928251,c,q)\land enroll(s,c,q)]\land s\not=928251 enroll(928251,c,q)enroll(s,c,q)]s=928251
  • T 15 = π S i d ( T 14 ) T_{15}=\pi_{Sid}(T_{14}) T15=πSid(T14) 对应整个 Q1 的一阶逻辑表达式。

Q2: 翻译这个一阶逻辑表达式有些难度,主要在于对全称量词 ∀ \forall 以及对逻辑蕴含 ⇒ \Rightarrow 的转化。因为关系代数没有表达 ∀ \forall 的表达式,小编已知所有的查询语言都不支持 ∀ \forall 表达,因为计算它的计算代价很大。在翻译之前我们需要用到:

  • 全称量词和存在量词的转化
    ( ∀ x ) [ f ( x ) ] ≡ ¬ ¬ ( ∀ x ) [ f ( x ) ]  双重否定 ≡ ¬ ( ∃ x ) [ ¬ f ( x ) ] \begin{aligned}(\forall x)[f(x)]&\equiv \neg\neg(\forall x)[f(x)]\ \text{双重否定}\\ &\equiv \neg(\exists x)[\neg f(x)] \end{aligned} (x)[f(x)]¬¬(x)[f(x)] 双重否定¬(x)[¬f(x)]
  • 逻辑蕴含的等价
    p ⇒ q ≡ ¬ ( p ∧ ¬ q ) ≡ ¬ p ∨ q p\Rightarrow q\equiv \neg (p\land \neg q)\equiv \neg p\lor q pq¬(p¬q)¬pq
  • 摩根定律 (De Morgan’s laws)
    ¬ ( p ∧ q ) ≡ ( ¬ p ∨ ¬ q ) , ¬ ( p ∨ q ) ≡ ( ¬ p ) ∧ ( ¬ q ) \neg(p\land q)\equiv (\neg p\lor \neg q), \neg(p\lor q)\equiv (\neg p)\land (\neg q) ¬(pq)(¬p¬q),¬(pq)(¬p)(¬q)
    变换一阶逻辑表达式:
    { s ∣ ( ∀ c ) ( ∀ q ) [ e n r o l l ( 928251 , c , q ) ⇒ e n r o l l ( s , c , q ) ] ∧ s ≠ 928251 } = { s ∣ ¬ ( ∃ c ) ( ∃ q ) [ ¬ ( e n r o l l ( 928251 , c , q ) ⇒ e n r o l l ( s , c , q ) ) ] ∧ s ≠ 928251 }  全称量词转化 = { s ∣ ¬ ( ∃ c ) ( ∃ q ) [ ¬ ( ¬ e n r o l l ( 928251 , c , q ) ∨ e n r o l l ( s , c , q ) ) ] ∧ s ≠ 928251 }  逻辑蕴含等价 = { s ∣ ¬ ( ∃ c ) ( ∃ q ) [ e n r o l l ( 928251 , c , q ) ∧ ¬ e n r o l l ( s , c , q ) ) ] ∧ s ≠ 928251 }  摩根定律 \begin{aligned}&\{s|(\forall c)(\forall q)[enroll(928251,c,q)\Rightarrow enroll(s,c,q)]\land s\not=928251\}\\ =&\{s|\neg(\exists c)(\exists q)[\neg(enroll(928251,c,q)\Rightarrow enroll(s,c,q))]\land s\not=928251\}\ \text{全称量词转化}\\ =& \{s|\neg(\exists c)(\exists q)[\neg(\neg enroll(928251,c,q)\lor enroll(s,c,q))]\land s\not=928251\}\ \text{逻辑蕴含等价}\\ =& \{s|\neg(\exists c)(\exists q)[enroll(928251,c,q)\land \neg enroll(s,c,q))]\land s\not=928251\}\ \text{摩根定律} \end{aligned} ==={s(c)(q)[enroll(928251,c,q)enroll(s,c,q)]s=928251}{s∣¬(c)(q)[¬(enroll(928251,c,q)enroll(s,c,q))]s=928251} 全称量词转化{s∣¬(c)(q)[¬(¬enroll(928251,c,q)enroll(s,c,q))]s=928251} 逻辑蕴含等价{s∣¬(c)(q)[enroll(928251,c,q)¬enroll(s,c,q))]s=928251} 摩根定律

学生表:Student(Sid, Name, Major, Birthdate)
课程表:Course(Cid, CName, Dept)
课程选修表:Enroll(Sid, Cid, Quarter, Grade)

翻译转化后的一阶逻辑表达式 { s ∣ ¬ ( ∃ c ) ( ∃ q ) [ e n r o l l ( 928251 , c , q ) ∧ ¬ e n r o l l ( s , c , q ) ) ] ∧ s ≠ 928251 } \{s|\neg(\exists c)(\exists q)[enroll(928251,c,q)\land \neg enroll(s,c,q))]\land s\not=928251\} {s∣¬(c)(q)[enroll(928251,c,q)¬enroll(s,c,q))]s=928251} 为关系代数表达式:

  • T 21 = π S i d , C i d , Q u a r t e r ( S t u d e n t × C o u r s e ) T_{21}=\pi_{Sid,Cid,Quarter}(Student\times Course) T21=πSid,Cid,Quarter(Student×Course) 表示全集 U U U (所有可能的选修信息),其中 × \times × 表示笛卡尔积。
  • T 22 = T 21 − T 12 T_{22}=T_{21}-T_{12} T22=T21T12 对应一阶逻辑表达式 ¬ e n r o l l ( s , c , q ) \neg enroll(s,c,q) ¬enroll(s,c,q),这里需要全集 U U U 来表达 negation ( ¬ \neg ¬)。
  • T 23 = T 11 ⋈ T 22 T_{23}=T_{11}\Join T_{22} T23=T11T22 对应一阶逻辑表达式 e n r o l l ( 928251 , c , q ) ∧ ¬ e n r o l l ( s , c , q ) enroll(928251,c,q)\land \neg enroll(s,c,q) enroll(928251,c,q)¬enroll(s,c,q),其中 ⋈ \Join 表示自然连接,等价于逻辑 “与” ( ∧ \land )。
  • T 24 = T 21 − T 23 T_{24}=T_{21}-T_{23} T24=T21T23 对应一阶逻辑表达式 ¬ ( ∃ c ) ( ∃ q ) [ e n r o l l ( 928251 , c , q ) ∧ ¬ e n r o l l ( s , c , q ) ) ] \neg(\exists c)(\exists q)[enroll(928251,c,q)\land \neg enroll(s,c,q))] ¬(c)(q)[enroll(928251,c,q)¬enroll(s,c,q))]
  • T 25 = σ S i d ≠ 928251 ( T 24 ) T_{25}=\sigma_{Sid\not= 928251}(T_{24}) T25=σSid=928251(T24) 对应一阶逻辑表达式 ¬ ( ∃ c ) ( ∃ q ) [ e n r o l l ( 928251 , c , q ) ∧ ¬ e n r o l l ( s , c , q ) ) ] ∧ s ≠ 928251 \neg(\exists c)(\exists q)[enroll(928251,c,q)\land \neg enroll(s,c,q))]\land s\not=928251 ¬(c)(q)[enroll(928251,c,q)¬enroll(s,c,q))]s=928251
  • T 26 = π S i d ( T 25 ) T_{26}=\pi_{Sid}(T_{25}) T26=πSid(T25) 对应整个转化后的 Q2 的一阶逻辑表达式。

Q3: { s ∣ ( ∀ c ) ( ∀ q ) [ e n r o l l ( s , c , q ) ⇒ e n r o l l ( 928251 , c , q ) ] ∧ s ≠ 928251 } \{s|(\forall c)(\forall q)[enroll(s,c,q)\Rightarrow enroll(928251,c,q)]\land s\not=928251\} {s(c)(q)[enroll(s,c,q)enroll(928251,c,q)]s=928251} ≡ \equiv { s ∣ ¬ ( ∃ c ) ( ∃ q ) [ e n r o l l ( s , c , q ) ∧ ¬ e n r o l l ( 928251 , c , q ) ] ∧ s ≠ 928251 } \{s|\neg(\exists c)(\exists q)[enroll(s,c,q)\land \neg enroll(928251,c,q)]\land s\not=928251\} {s∣¬(c)(q)[enroll(s,c,q)¬enroll(928251,c,q)]s=928251},这里直接给出关系代数表达式:

  • T 31 = π C i d , Q u a r t e r ( S t u d e n t × C o u r s e ) T_{31}=\pi_{Cid,Quarter}(Student\times Course) T31=πCid,Quarter(Student×Course)
  • T 32 = T 31 − T 11 T_{32}=T_{31}-T_{11} T32=T31T11
  • T 33 = T 12 ⋈ T 32 T_{33}=T_{12}\Join T_{32} T33=T12T32
  • T 34 = T 21 − T 33 T_{34}=T_{21}-T_{33} T34=T21T33
  • T 35 = σ S i d ≠ 928251 ( T 34 ) T_{35}=\sigma_{Sid\not=928251}(T_{34}) T35=σSid=928251(T34)
  • T 36 = π S i d ( T 35 ) T_{36}=\pi_{Sid}(T_{35}) T36=πSid(T35)

Q4: 答案为 Q3Q2 的逻辑 “与”:
T 41 = T 26 ⋈ T 36 T_{41}=T_{26}\Join T_{36} T41=T26T36

Step3. 关系代数 --> SQL 查询

学生表:Student(Sid, Name, Major, Birthdate)
课程表:Course(Cid, CName, Dept)
课程选修表:Enroll(Sid, Cid, Quarter, Grade)

Q2 为例子来写查询
T 21 = π S i d , C i d , Q u a r t e r ( S t u d e n t × C o u r s e ) T_{21}=\pi_{Sid,Cid,Quarter}(Student\times Course) T21=πSid,Cid,Quarter(Student×Course) :

CREATE VIEW T21 AS
SELECT Sid, Cid, Quarter
FROM Student, Course;

T 22 = T 21 − T 12 T_{22}=T_{21}-T_{12} T22=T21T12,其中 T 12 = π S i d , C i d , Q u a r t e r ( E n r o l l ) T_{12}=\pi_{Sid,Cid,Quarter}(Enroll) T12=πSid,Cid,Quarter(Enroll):

CREATE VIEW T22 AS
SELECT DISTINCT T21.Sid, T21.Cid, T21.Quarter 
EXCEPT
SELECT DISTINCT Sid, Cid, Quarter FROM Enroll;

T 23 = T 11 ⋈ T 22 T_{23}=T_{11}\Join T_{22} T23=T11T22,其中 T 11 : = π C i d , Q u a r t e r ( σ S i d = 928251 ( E n r o l l ) ) ) T_{11}:=\pi_{Cid,Quarter}(\sigma_{Sid=928251}(Enroll))) T11:=πCid,Quarter(σSid=928251(Enroll))):

CREATE VIEW T11 AS
SELECT Cid, Quater 
FROM Enroll
WHERE Sid = 928251;
CREATE VIEW T23 AS
SELECT T11.Sid, T11.Cid, T11.Quarter
FROM T11
NATURAL JOIN T22;

T 24 = T 21 − T 23 T_{24}=T_{21}-T_{23} T24=T21T23:

CREATE VIEW T24 AS
SELECT DISTINCT *
FROM T21
EXCEPT
SELECT DISTINCT *
FROM T23;

上面的 SELECT DISTINCT * 也可以是 SELECT DISTINCT Sid, Cid, Quarter

T 25 = σ S i d ≠ 928251 ( T 24 ) T_{25}=\sigma_{Sid\not= 928251}(T_{24}) T25=σSid=928251(T24), T 26 = π S i d ( T 25 ) T_{26}=\pi_{Sid}(T_{25}) T26=πSid(T25):

SELECT DISTINCT Sid
FROM T24
WHERE Sid != 928521;

关系代数到 SQL 的对应表总结

这里根据 set semantics (集合语义) 给出的对应表。

关系代数SQL 语法
σ S P ( R ) = { t ∣ t ∈ R ∧ t  satisfies  S P } \sigma_{SP}(R)=\{t\mid t\in R\land t\text{ satisfies }SP\} σSP(R)={ttRt satisfies SP}SELECT DISTINCT * FROM R WHERE SP
π A 1 , ⋯   , A n ( R ) = { ( r . A 1 , ⋯   , r . A n ) ∣ r ∈ R } \pi_{A_1,\cdots,A_n}(R)=\{(r.{A_1},\cdots,r.{A_n})\mid r\in R\} πA1,,An(R)={(r.A1,,r.An)rR}SELECT DISTINCT A1, ..., An FROM R
R × S = { ( t . A 1 , ⋯   , t . A n , r . B 1 , ⋯   , r . B n ) ∣ t ∈ R ∧ r ∈ S } R\times S=\{(t.A_1,\cdots,t.A_n,r.B_1,\cdots,r.B_n)\mid t\in R\land r\in S\} R×S={(t.A1,,t.An,r.B1,,r.Bn)tRrS}SELECT DISTINCT * FROM R, S
R ⋈ S P S = { t ∣ t ∈ R × S ∧ t  satisfies  S P } R\Join_{SP}S=\{t\mid t\in R\times S\land t\text{ satisfies }SP\} RSPS={ttR×St satisfies SP}SELECT DISTINCT * FROM R, S WHERE SP
R ⋈ S = { t = ( A 1 , ⋯   , A n ) ∣ t ∈ R × S ∧ R . A 1 = S . A 1 ∧ ⋯ ∧ R . A n = S . A n } R\Join S=\{t=(A_1,\cdots,A_n)\mid t\in R\times S\land R.A_1=S.A_1\land\cdots\land R.A_n=S.A_n\} RS={t=(A1,,An)tR×SR.A1=S.A1R.An=S.An}SELECT DISTINCT * FROM R NATURAL JOIN S
R ⋈ R . A 1 = S . A 1 ∧ ⋯ ∧ R . A n = S . A n S R\Join_{R.A_1=S.A_1\land\cdots\land R.A_n=S.A_n} S RR.A1=S.A1R.An=S.AnSSELECT DISTINCT * FROM R JOIN S USING (A1, ..., An)
R  ⟕ S P   S R{\ ⟕}_{SP}\ S R SP SSELECT DISTINCT * FROM R LEFT OUTER JOIN S ON SP
R  ⟖ S P   S R{\ ⟖}_{SP}\ S R SP SSELECT DISTINCT * FROM R RIGHT OUTER JOIN S ON SP
R  ⟗ S P   S R{\ ⟗}_{SP}\ S R SP SSELECT DISTINCT * FROM R FULL OUTER OUTER JOIN S ON SP
R ∪ S = { t ∣ t ∈ R ∨ t ∈ S } R\cup S=\{t\mid t\in R\lor t\in S\} RS={ttRtS}SELECT DISTINCT * FROM R UNION SELECT DISTINCT * FROM S
R ∩ S = { t ∣ t ∈ R ∧ t ∈ S } R\cap S=\{t\mid t\in R\land t\in S\} RS={ttRtS}SELECT DISTINCT * FROM R INTERSECT SELECT DISTINCT * FROM S
R − S = { t ∣ t ∈ R ∧ t ∉ S } R- S=\{t\mid t\in R\land t\not\in S\} RS={ttRtS}SELECT DISTINCT * FROM R EXCEPT SELECT DISTINCT * FROM S

不定期更新专业知识和有趣的东西,欢迎反馈、点赞、加星

您的鼓励和支持是我坚持创作的最大动力!ღ( ´・ᴗ・` )

Reference

  1. Introduction to Database Systems (SoSe 2024) by Maria-Esther Vidal.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值